diff --git a/rust-version b/rust-version index 4b5e8c4412..601cdfe8ef 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -be8e82435eb04fbe75ed5286b52735366e160bed +48c2cee70232ecc3a6a8e285b2e15620b39f82a7 diff --git a/src/machine.rs b/src/machine.rs index cc6a15d3f7..db8e2b83b5 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -575,8 +575,11 @@ pub struct MiriMachine<'tcx> { /// Mapping extern static names to their pointer. pub(crate) extern_statics: FxHashMap, + /// Statics with `import_linkage` have an extra indirection + /// () so we keep them in a separate table. + pub(crate) extern_statics_imports: FxHashMap, /// A pointer to the allocation we provide for non-existent weak symbols. - pub(crate) missing_weak_symbol: Option, + pub(crate) extern_static_weak_import_default: Option, /// The random number generator used for resolving non-determinism. /// Needs to be queried by ptr_to_int, hence needs interior mutability. @@ -780,7 +783,8 @@ impl<'tcx> MiriMachine<'tcx> { backtrace_style: config.backtrace_style, user_relevant_crates, extern_statics: FxHashMap::default(), - missing_weak_symbol: None, + extern_statics_imports: FxHashMap::default(), + extern_static_weak_import_default: None, rng: RefCell::new(rng), allocator: (!config.native_lib.is_empty()) .then(|| Rc::new(RefCell::new(crate::alloc::isolated_alloc::IsolatedAlloc::new()))), @@ -905,12 +909,6 @@ impl<'tcx> MiriMachine<'tcx> { interp_ok(()) } - pub(crate) fn add_extern_static(ecx: &mut MiriInterpCx<'tcx>, name: &str, ptr: Pointer) { - // This got just allocated, so there definitely is a pointer here. - let ptr = ptr.into_pointer_or_addr().unwrap(); - ecx.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); - } - pub(crate) fn communicate(&self) -> bool { self.isolated_op == IsolatedOp::Allow } @@ -1024,7 +1022,8 @@ impl VisitProvenance for MiriMachine<'_> { argv, cmd_line, extern_statics, - missing_weak_symbol, + extern_statics_imports, + extern_static_weak_import_default, dirs, borrow_tracker, data_race, @@ -1087,10 +1086,9 @@ impl VisitProvenance for MiriMachine<'_> { argc.visit_provenance(visit); argv.visit_provenance(visit); cmd_line.visit_provenance(visit); - missing_weak_symbol.visit_provenance(visit); - for ptr in extern_statics.values() { - ptr.visit_provenance(visit); - } + extern_static_weak_import_default.visit_provenance(visit); + extern_statics.visit_provenance(visit); + extern_statics_imports.visit_provenance(visit); } } @@ -1391,7 +1389,13 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { let extern_decl_layout = ecx.tcx.layout_of(ecx.typing_env().as_query_input(def_ty)).unwrap(); - if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) { + // Look up the `ptr` in the right map, depending on whether this is an "import" + // static or a real one. + let ptr = match ecx.tcx.codegen_fn_attrs(def_id).import_linkage { + None => ecx.machine.extern_statics.get(&link_name), + Some(_) => ecx.machine.extern_statics_imports.get(&link_name), + }; + if let Some(&ptr) = ptr { // 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. @@ -1429,7 +1433,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ); interp_ok( ecx.machine - .missing_weak_symbol + .extern_static_weak_import_default .expect("`missing_weak_symbol` should have been initialized"), ) } else { diff --git a/src/provenance_gc.rs b/src/provenance_gc.rs index 8158a04692..44485858dd 100644 --- a/src/provenance_gc.rs +++ b/src/provenance_gc.rs @@ -1,7 +1,8 @@ use std::collections::BTreeMap; use rustc_data_structures::either::Either; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_span::Symbol; use crate::*; @@ -21,7 +22,7 @@ macro_rules! no_provenance { )+ } } -no_provenance!(i8 i16 i32 i64 isize u8 u16 u32 u64 usize bool ThreadId Deadline); +no_provenance!(i8 i16 i32 i64 isize u8 u16 u32 u64 usize bool ThreadId Deadline Symbol); impl VisitProvenance for &'static str { fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {} @@ -61,6 +62,15 @@ impl VisitProvenance for BTreeMap } } +impl VisitProvenance for FxHashMap { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + self.iter().for_each(|(key, value)| { + key.visit_provenance(visit); + value.visit_provenance(visit); + }); + } +} + impl VisitProvenance for std::cell::RefCell { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { self.borrow().visit_provenance(visit) diff --git a/src/shims/extern_static.rs b/src/shims/extern_static.rs index 9d8a9d1083..a8a95010a7 100644 --- a/src/shims/extern_static.rs +++ b/src/shims/extern_static.rs @@ -1,10 +1,17 @@ //! Provides the `extern static` that this platform expects. +use rustc_span::Symbol; use rustc_target::spec::Os; use crate::*; impl<'tcx> MiriMachine<'tcx> { + fn add_extern_static(ecx: &mut MiriInterpCx<'tcx>, name: &str, ptr: Pointer) { + // This got just allocated, so there definitely is a pointer here. + let ptr = ptr.into_pointer_or_addr().unwrap(); + ecx.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); + } + fn alloc_extern_static( ecx: &mut MiriInterpCx<'tcx>, name: &str, @@ -16,17 +23,27 @@ impl<'tcx> MiriMachine<'tcx> { interp_ok(()) } - /// Extern statics that are initialized with function pointers to the symbols of the same name. - fn weak_symbol_extern_statics( + /// Make `ptr` available as a weak symbol with the given name. + fn add_weak_symbol( ecx: &mut MiriInterpCx<'tcx>, - names: &[&str], + name: &str, + ptr: Pointer, ) -> InterpResult<'tcx> { + // Allocate the extra indirection place and add it to the map. + let layout = ecx.machine.layouts.mut_raw_ptr; + let place = ecx.allocate(layout, MiriMemoryKind::ExternStatic.into())?; + ecx.write_scalar(Scalar::from_maybe_pointer(ptr, ecx), &place)?; + let weak_ptr = place.ptr().into_pointer_or_addr().unwrap(); + ecx.machine.extern_statics_imports.try_insert(Symbol::intern(name), weak_ptr).unwrap(); + interp_ok(()) + } + + /// Extern statics that are initialized with function pointers to the symbols of the same name. + fn weak_fn_symbols(ecx: &mut MiriInterpCx<'tcx>, names: &[&str]) -> InterpResult<'tcx> { for name in names { assert!(ecx.is_dyn_sym(name), "{name} is not a dynamic symbol"); - let layout = ecx.machine.layouts.const_raw_ptr; let ptr = ecx.fn_ptr(FnVal::Other(DynSym::from_str(name))); - let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, ecx), layout); - Self::alloc_extern_static(ecx, name, val)?; + Self::add_weak_symbol(ecx, name, ptr.into())?; } interp_ok(()) } @@ -37,17 +54,16 @@ impl<'tcx> MiriMachine<'tcx> { // "environ" is mandated by POSIX. let environ = ecx.machine.env_vars.unix().environ(); Self::add_extern_static(ecx, "environ", environ); + // We also provide it as a weak symbol, which is needed on FreeBSD. + Self::add_weak_symbol(ecx, "environ", environ)?; } match &ecx.tcx.sess.target.os { Os::Linux => { - Self::weak_symbol_extern_statics(ecx, &["getrandom", "gettid", "statx", "strlen"])?; + Self::weak_fn_symbols(ecx, &["getrandom", "gettid", "statx", "strlen"])?; } Os::Android => { - Self::weak_symbol_extern_statics( - ecx, - &["signal", "getrandom", "gettid", "futimens"], - )?; + Self::weak_fn_symbols(ecx, &["signal", "getrandom", "gettid", "futimens"])?; } Os::Windows => { // "_tls_used" @@ -56,7 +72,7 @@ impl<'tcx> MiriMachine<'tcx> { Self::alloc_extern_static(ecx, "_tls_used", val)?; } Os::Illumos | Os::Solaris => { - Self::weak_symbol_extern_statics(ecx, &["pthread_setname_np"])?; + Self::weak_fn_symbols(ecx, &["pthread_setname_np"])?; } _ => {} // No "extern statics" supported on this target. } @@ -64,7 +80,8 @@ impl<'tcx> MiriMachine<'tcx> { // Also initialize `missing_weak_symbol`. let place = ecx.allocate(ecx.machine.layouts.usize, MiriMemoryKind::ExternStatic.into())?; ecx.write_null(&place)?; - ecx.machine.missing_weak_symbol = Some(place.ptr().into_pointer_or_addr().unwrap()); + ecx.machine.extern_static_weak_import_default = + Some(place.ptr().into_pointer_or_addr().unwrap()); interp_ok(()) } diff --git a/tests/pass/shims/env/var.rs b/tests/pass/shims/env/var.rs index 31e59c4a41..7e959a993d 100644 --- a/tests/pass/shims/env/var.rs +++ b/tests/pass/shims/env/var.rs @@ -1,4 +1,3 @@ -//@compile-flags: -Zmiri-deterministic-concurrency use std::{env, thread}; fn main() { @@ -26,8 +25,6 @@ fn main() { println!("{:#?}", env::vars().collect::>()); // Do things concurrently, to make sure there's no data race. - // We disable preemption to make sure the lock is not contended; - // that means we don't hit e.g. the futex codepath on Android (which we don't support). let t = thread::spawn(|| { env::set_var("MIRI_TEST", "42"); });