diff --git a/bench-cargo-miri/mse/src/main.rs b/bench-cargo-miri/mse/src/main.rs index 696de93442..b4ad157510 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); } } diff --git a/rust-version b/rust-version index f28fce1af2..82d8da1d03 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d9051341a1c142542a3f7dab509266606c775382 +e86c9e6ef8be7ddec0360f20aae7d86c69c59a83 diff --git a/src/eval.rs b/src/eval.rs index cc02100dd3..267b79d0eb 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 @@ -90,14 +91,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 +109,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 +135,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 +148,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 +159,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/intptrcast.rs b/src/intptrcast.rs index 059d8217fa..375ebf0996 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 } diff --git a/src/machine.rs b/src/machine.rs index b5c76070ae..331e75414a 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,10 +13,9 @@ use rustc::mir; use rustc::ty::{ self, layout::{LayoutOf, Size}, - Ty, TyCtxt, + Ty, }; use rustc_ast::attr; -use rustc_hir::def_id::DefId; use rustc_span::{source_map::Span, symbol::sym}; use crate::*; @@ -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, } @@ -74,7 +74,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 +89,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 +298,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>( @@ -433,7 +461,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 3fd895576e..10f7492165 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 e930af7f46..11c5a882be 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(); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a51f8c4571..9a511aaed5 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.