diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 4b447229c5f61..739dbcc5aba64 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -107,6 +107,14 @@ impl interpret::AllocMap for FxIndexMap { FxIndexMap::contains_key(self, k) } + #[inline(always)] + fn contains_key_ref(&self, k: &Q) -> bool + where + K: Borrow, + { + FxIndexMap::contains_key(self, k) + } + #[inline(always)] fn insert(&mut self, k: K, v: V) -> Option { FxIndexMap::insert(self, k, v) diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 61fe9151d8b41..6617f6f2ffb68 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -49,6 +49,14 @@ pub trait AllocMap { where K: Borrow; + /// Callers should prefer [`AllocMap::contains_key`] when it is possible to call because it may + /// be more efficient. This function exists for callers that only have a shared reference + /// (which might make it slightly less efficient than `contains_key`, e.g. if + /// the data is stored inside a `RefCell`). + fn contains_key_ref(&self, k: &Q) -> bool + where + K: Borrow; + /// Inserts a new entry into the map. fn insert(&mut self, k: K, v: V) -> Option; diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 16905e93bf1f8..d5b165a7415b3 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -692,6 +692,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok((&mut alloc.extra, machine)) } + /// Check whether an allocation is live. This is faster than calling + /// [`InterpCx::get_alloc_info`] if all you need to check is whether the kind is + /// [`AllocKind::Dead`] because it doesn't have to look up the type and layout of statics. + pub fn is_alloc_live(&self, id: AllocId) -> bool { + self.tcx.try_get_global_alloc(id).is_some() + || self.memory.alloc_map.contains_key_ref(&id) + || self.memory.extra_fn_ptr_map.contains_key(&id) + } + /// Obtain the size and alignment of an allocation, even if that allocation has /// been deallocated. pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind) { diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index b87c6885e04c8..e360fb3eaaf3c 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -525,13 +525,6 @@ impl<'tcx> TyCtxt<'tcx> { self.alloc_map.lock().reserve() } - /// Miri's provenance GC needs to see all live allocations. The interpreter manages most - /// allocations but some are managed by [`TyCtxt`] and without this method the interpreter - /// doesn't know their [`AllocId`]s are in use. - pub fn iter_allocs(self, func: F) { - self.alloc_map.lock().alloc_map.keys().copied().for_each(func) - } - /// Reserves a new ID *if* this allocation has not been dedup-reserved before. /// Should only be used for "symbolic" allocations (function pointers, vtables, statics), we /// don't want to dedup IDs for "real" memory! diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 89dbf40c7b4d0..1fa76f9b2ff6c 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -18,7 +18,10 @@ use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt, Variance}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_target::abi::FieldIdx; use stable_mir::mir::mono::InstanceDef; -use stable_mir::mir::{Body, CopyNonOverlapping, Statement, UserTypeProjection, VariantIdx}; +use stable_mir::mir::{ + Body, ConstOperand, CopyNonOverlapping, Statement, UserTypeProjection, VarDebugInfoFragment, + VariantIdx, +}; use stable_mir::ty::{ AdtDef, AdtKind, ClosureDef, ClosureKind, Const, ConstId, ConstantKind, EarlyParamRegion, FloatTy, FnDef, GenericArgs, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span, @@ -412,10 +415,24 @@ impl<'tcx> Stable<'tcx> for mir::Body<'tcx> { }) .collect(), self.arg_count, + self.var_debug_info.iter().map(|info| info.stable(tables)).collect(), ) } } +impl<'tcx> Stable<'tcx> for mir::VarDebugInfo<'tcx> { + type T = stable_mir::mir::VarDebugInfo; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + stable_mir::mir::VarDebugInfo { + name: self.name.to_string(), + source_info: self.source_info.stable(tables), + composite: self.composite.as_ref().map(|composite| composite.stable(tables)), + value: self.value.stable(tables), + argument_index: self.argument_index, + } + } +} + impl<'tcx> Stable<'tcx> for mir::Statement<'tcx> { type T = stable_mir::mir::Statement; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { @@ -423,6 +440,42 @@ impl<'tcx> Stable<'tcx> for mir::Statement<'tcx> { } } +impl<'tcx> Stable<'tcx> for mir::SourceInfo { + type T = stable_mir::mir::SourceInfo; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + stable_mir::mir::SourceInfo { span: self.span.stable(tables), scope: self.scope.into() } + } +} + +impl<'tcx> Stable<'tcx> for mir::VarDebugInfoFragment<'tcx> { + type T = stable_mir::mir::VarDebugInfoFragment; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + VarDebugInfoFragment { + ty: self.ty.stable(tables), + projection: self.projection.iter().map(|e| e.stable(tables)).collect(), + } + } +} + +impl<'tcx> Stable<'tcx> for mir::VarDebugInfoContents<'tcx> { + type T = stable_mir::mir::VarDebugInfoContents; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + mir::VarDebugInfoContents::Place(place) => { + stable_mir::mir::VarDebugInfoContents::Place(place.stable(tables)) + } + mir::VarDebugInfoContents::Const(const_operand) => { + let op = ConstOperand { + span: const_operand.span.stable(tables), + user_ty: const_operand.user_ty.map(|index| index.as_usize()), + const_: const_operand.const_.stable(tables), + }; + stable_mir::mir::VarDebugInfoContents::Const(op) + } + } + } +} + impl<'tcx> Stable<'tcx> for mir::StatementKind<'tcx> { type T = stable_mir::mir::StatementKind; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 771aec4de7b17..9b0fedba0923f 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1587,7 +1587,6 @@ supported_targets! { ("armv7r-none-eabihf", armv7r_none_eabihf), ("x86_64-pc-solaris", x86_64_pc_solaris), - ("x86_64-sun-solaris", x86_64_sun_solaris), ("sparcv9-sun-solaris", sparcv9_sun_solaris), ("x86_64-unknown-illumos", x86_64_unknown_illumos), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/targets/x86_64_sun_solaris.rs deleted file mode 100644 index cca099d3bbf65..0000000000000 --- a/compiler/rustc_target/src/spec/targets/x86_64_sun_solaris.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::spec::{base, Cc, LinkerFlavor, StackProbeType, Target}; - -pub fn target() -> Target { - let mut base = base::solaris::opts(); - base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64"]); - base.cpu = "x86-64".into(); - base.plt_by_default = false; - base.vendor = "sun".into(); - base.max_atomic_width = Some(64); - base.stack_probes = StackProbeType::X86; - - Target { - llvm_target: "x86_64-pc-solaris".into(), - pointer_width: 64, - data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - .into(), - arch: "x86_64".into(), - options: base, - } -} diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index e6e05d0adc627..9119792e32439 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -1010,7 +1010,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> { let Goal { param_env, predicate } = goal.goal(); - // For bound predicates we simply call `infcx.replace_bound_vars_with_placeholders` + // For bound predicates we simply call `infcx.instantiate_binder_with_placeholders` // and then prove the resulting predicate as a nested goal. let trait_ref = match predicate.kind().no_bound_vars() { Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref, diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index ec2fb4888ea6b..737acfbc60051 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -16,7 +16,7 @@ use rustc_target::spec::abi::Abi as SpecAbi; use std::iter; -pub fn provide(providers: &mut Providers) { +pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers }; } diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index ffeeae668587e..0a34aef16ae0f 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -8,7 +8,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, GenericArgs, ImplTraitInTraitData, Ty, TyCtxt}; use rustc_span::symbol::kw; -pub fn provide(providers: &mut Providers) { +pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { associated_item, associated_item_def_ids, diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 35487d3b6982b..9ced50c8e138c 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -17,7 +17,7 @@ use crate::errors::{GenericConstantTooComplex, GenericConstantTooComplexSub}; /// Destructures array, ADT or tuple constants into the constants /// of their fields. -pub(crate) fn destructure_const<'tcx>( +fn destructure_const<'tcx>( tcx: TyCtxt<'tcx>, const_: ty::Const<'tcx>, ) -> ty::DestructuredConst<'tcx> { @@ -396,7 +396,7 @@ impl<'a, 'tcx> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> { } /// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead. -pub fn thir_abstract_const( +fn thir_abstract_const( tcx: TyCtxt<'_>, def: LocalDefId, ) -> Result>>, ErrorGuaranteed> { @@ -428,6 +428,6 @@ pub fn thir_abstract_const( Ok(Some(ty::EarlyBinder::bind(recurse_build(tcx, body, body_id, root_span)?))) } -pub fn provide(providers: &mut Providers) { +pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { destructure_const, thir_abstract_const, ..*providers }; } diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 24afd7dc35782..6cf5aa6f2fb36 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -7,7 +7,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; use std::iter; -pub fn provide(providers: &mut Providers) { +pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { assumed_wf_types, assumed_wf_types_for_rpitit: |tcx, def_id| { diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 1487f40fd9941..31f6a56eaeb40 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -61,7 +61,7 @@ fn resolve_instance<'tcx>( Ok(Some(Instance { def, args })) }; - debug!("inner_resolve_instance: result={:?}", result); + debug!("resolve_instance: result={:?}", result); result } @@ -328,6 +328,6 @@ fn resolve_associated_item<'tcx>( }) } -pub fn provide(providers: &mut Providers) { +pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { resolve_instance, ..*providers }; } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 52f723eba80ef..b09566e166829 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -24,7 +24,7 @@ use crate::errors::{ }; use crate::layout_sanity_check::sanity_check_layout; -pub fn provide(providers: &mut Providers) { +pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { layout_of, ..*providers }; } @@ -65,7 +65,11 @@ fn layout_of<'tcx>( let layout = layout_of_uncached(&cx, ty)?; let layout = TyAndLayout { ty, layout }; - record_layout_for_printing(&cx, layout); + // If we are running with `-Zprint-type-sizes`, maybe record layouts + // for dumping later. + if cx.tcx.sess.opts.unstable_opts.print_type_sizes { + record_layout_for_printing(&cx, layout); + } sanity_check_layout(&cx, &layout); @@ -911,21 +915,7 @@ fn coroutine_layout<'tcx>( Ok(layout) } -/// This is invoked by the `layout_of` query to record the final -/// layout of each type. -#[inline(always)] fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: TyAndLayout<'tcx>) { - // If we are running with `-Zprint-type-sizes`, maybe record layouts - // for dumping later. - if cx.tcx.sess.opts.unstable_opts.print_type_sizes { - record_layout_for_printing_outlined(cx, layout) - } -} - -fn record_layout_for_printing_outlined<'tcx>( - cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, - layout: TyAndLayout<'tcx>, -) { // Ignore layouts that are done with non-empty environments or // non-monomorphic layouts, as the user only wants to see the stuff // resulting from the final codegen session. diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 8de058f02c9e7..8321732b76630 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -10,11 +10,11 @@ #![allow(internal_features)] #![feature(assert_matches)] #![feature(associated_type_defaults)] +#![feature(box_patterns)] +#![feature(if_let_guard)] #![feature(iterator_try_collect)] #![feature(let_chains)] -#![feature(if_let_guard)] #![feature(never_type)] -#![feature(box_patterns)] #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] @@ -34,13 +34,13 @@ mod common_traits; mod consts; mod errors; mod implied_bounds; -pub mod instance; +mod instance; mod layout; mod layout_sanity_check; mod needs_drop; mod opaque_types; -pub mod representability; -pub mod sig_types; +mod representability; +mod sig_types; mod structural_match; mod ty; diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index f34e0df2c75ef..3aaa2e73bb805 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -6,7 +6,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, Representability, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; -pub fn provide(providers: &mut Providers) { +pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { representability, representability_adt_ty, params_in_repr, ..*providers }; } diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs index ccdc6120196ac..268639a7f4441 100644 --- a/compiler/rustc_ty_utils/src/sig_types.rs +++ b/compiler/rustc_ty_utils/src/sig_types.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::Span; use rustc_type_ir::visit::TypeVisitable; -pub trait SpannedTypeVisitor<'tcx> { +pub(crate) trait SpannedTypeVisitor<'tcx> { type BreakTy = !; fn visit( &mut self, @@ -17,7 +17,7 @@ pub trait SpannedTypeVisitor<'tcx> { ) -> ControlFlow; } -pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( +pub(crate) fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( tcx: TyCtxt<'tcx>, item: LocalDefId, visitor: &mut V, diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs index 215acbe2c8f85..6e7a9887774f8 100644 --- a/compiler/rustc_ty_utils/src/structural_match.rs +++ b/compiler/rustc_ty_utils/src/structural_match.rs @@ -39,6 +39,6 @@ fn has_structural_eq_impls<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool { ocx.select_all_or_error().is_empty() } -pub fn provide(providers: &mut Providers) { +pub(crate) fn provide(providers: &mut Providers) { providers.has_structural_eq_impls = has_structural_eq_impls; } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 485bde735d8f6..b7c75da7301f4 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -351,7 +351,7 @@ fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> BitSet, } impl Body { @@ -24,14 +26,19 @@ impl Body { /// /// A constructor is required to build a `Body` from outside the crate /// because the `arg_count` and `locals` fields are private. - pub fn new(blocks: Vec, locals: LocalDecls, arg_count: usize) -> Self { + pub fn new( + blocks: Vec, + locals: LocalDecls, + arg_count: usize, + var_debug_info: Vec, + ) -> Self { // If locals doesn't contain enough entries, it can lead to panics in // `ret_local`, `arg_locals`, and `inner_locals`. assert!( locals.len() > arg_count, "A Body must contain at least a local for the return value and each of the function's arguments" ); - Self { blocks, locals, arg_count } + Self { blocks, locals, arg_count, var_debug_info } } /// Return local that holds this function's return value. @@ -425,6 +432,42 @@ pub struct Place { pub projection: Vec, } +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct VarDebugInfo { + pub name: Symbol, + pub source_info: SourceInfo, + pub composite: Option, + pub value: VarDebugInfoContents, + pub argument_index: Option, +} + +pub type SourceScope = u32; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SourceInfo { + pub span: Span, + pub scope: SourceScope, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct VarDebugInfoFragment { + pub ty: Ty, + pub projection: Vec, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum VarDebugInfoContents { + Place(Place), + Const(ConstOperand), +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ConstOperand { + pub span: Span, + pub user_ty: Option, + pub const_: Const, +} + // In MIR ProjectionElem is parameterized on the second Field argument and the Index argument. This // is so it can be used for both Places (for which the projection elements are of type // ProjectionElem) and user-provided type annotations (for which the projection elements diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index 40bedd67352f7..d90808725ae40 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -128,8 +128,12 @@ pub trait MirVisitor { self.super_assert_msg(msg, location) } + fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo) { + self.super_var_debug_info(var_debug_info); + } + fn super_body(&mut self, body: &Body) { - let Body { blocks, locals: _, arg_count } = body; + let Body { blocks, locals: _, arg_count, var_debug_info } = body; for bb in blocks { self.visit_basic_block(bb); @@ -145,6 +149,10 @@ pub trait MirVisitor { for (idx, arg) in body.inner_locals().iter().enumerate() { self.visit_local_decl(idx + local_start, arg) } + + for info in var_debug_info.iter() { + self.visit_var_debug_info(info); + } } fn super_basic_block(&mut self, bb: &BasicBlock) { @@ -382,6 +390,24 @@ pub trait MirVisitor { let _ = args; } + fn super_var_debug_info(&mut self, var_debug_info: &VarDebugInfo) { + let VarDebugInfo { source_info, composite, value, name: _, argument_index: _ } = + var_debug_info; + self.visit_span(&source_info.span); + let location = Location(source_info.span); + if let Some(composite) = composite { + self.visit_ty(&composite.ty, location); + } + match value { + VarDebugInfoContents::Place(place) => { + self.visit_place(place, PlaceContext::NON_USE, location); + } + VarDebugInfoContents::Const(constant) => { + self.visit_const(&constant.const_, location); + } + } + } + fn super_assert_msg(&mut self, msg: &AssertMessage, location: Location) { match msg { AssertMessage::BoundsCheck { len, index } => { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 254fbc72a8c7e..fa57533599f8e 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -49,9 +49,9 @@ const MIR_OPT_BLESS_TARGET_MAPPING: &[(&str, &str)] = &[ ("i686-unknown-linux-musl", "x86_64-unknown-linux-musl"), ("i686-pc-windows-msvc", "x86_64-pc-windows-msvc"), ("i686-pc-windows-gnu", "x86_64-pc-windows-gnu"), - ("i686-apple-darwin", "x86_64-apple-darwin"), // ARM Macs don't have a corresponding 32-bit target that they can (easily) // build for, so there is no entry for "aarch64-apple-darwin" here. + // Likewise, i686 for macOS is no longer possible to build. ]; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index 01b46118b9c1e..3f4e025111ade 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -48,9 +48,6 @@ ENV \ AR_x86_64_pc_solaris=x86_64-pc-solaris2.10-ar \ CC_x86_64_pc_solaris=x86_64-pc-solaris2.10-gcc \ CXX_x86_64_pc_solaris=x86_64-pc-solaris2.10-g++ \ - AR_x86_64_sun_solaris=x86_64-sun-solaris2.10-ar \ - CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \ - CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++ \ CC_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-gcc-9 \ CXX_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-g++-9 \ AR_x86_64_fortanix_unknown_sgx=ar \ @@ -84,8 +81,6 @@ COPY host-x86_64/dist-various-2/build-fuchsia-toolchain.sh /tmp/ RUN /tmp/build-fuchsia-toolchain.sh COPY host-x86_64/dist-various-2/build-solaris-toolchain.sh /tmp/ RUN /tmp/build-solaris-toolchain.sh x86_64 amd64 solaris-i386 pc -# Build deprecated target 'x86_64-sun-solaris2.10' until removed -RUN /tmp/build-solaris-toolchain.sh x86_64 amd64 solaris-i386 sun RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc sun COPY host-x86_64/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/ RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh @@ -120,7 +115,6 @@ ENV TARGETS=$TARGETS,wasm32-wasi ENV TARGETS=$TARGETS,wasm32-wasi-preview1-threads ENV TARGETS=$TARGETS,sparcv9-sun-solaris ENV TARGETS=$TARGETS,x86_64-pc-solaris -ENV TARGETS=$TARGETS,x86_64-sun-solaris ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32 ENV TARGETS=$TARGETS,x86_64-fortanix-unknown-sgx ENV TARGETS=$TARGETS,nvptx64-nvidia-cuda diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index 821a09feb2d53..205ee263217ad 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -25,7 +25,16 @@ cat /tmp/toolstate/toolstates.json python3 "$X_PY" test --stage 2 check-tools python3 "$X_PY" test --stage 2 src/tools/clippy python3 "$X_PY" test --stage 2 src/tools/rustfmt -python3 "$X_PY" test --stage 2 src/tools/miri + +# Testing Miri is a bit more complicated. +# We set the GC interval to the shortest possible value (0 would be off) to increase the chance +# that bugs which only surface when the GC runs at a specific time are more likely to cause CI to fail. +# This significantly increases the runtime of our test suite, or we'd do this in PR CI too. +if [[ -z "${PR_CI_JOB:-}" ]]; then + MIRIFLAGS=-Zmiri-provenance-gc=1 python3 "$X_PY" test --stage 2 src/tools/miri +else + python3 "$X_PY" test --stage 2 src/tools/miri +fi # We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc. # Also cover some other targets via cross-testing, in particular all tier 1 targets. export BOOTSTRAP_SKIP_TARGET_SANITY=1 # we don't need `cc` for these targets diff --git a/src/doc/book b/src/doc/book index 5b6c1ceaa62ec..71352deb20727 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 5b6c1ceaa62ecbd6caef08df39b33b3938e99deb +Subproject commit 71352deb20727b4dda9ebfe8182709d5bf17dfea diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 311b84962016b..a6581246f9683 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 311b84962016b28c75525c86e7b3f49fd9101a39 +Subproject commit a6581246f96837113968c02187db24f742af3908 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 77dbe5782b248..ddb8b1309f9e9 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 77dbe5782b2488af3bb489ad702eaff438f465bf +Subproject commit ddb8b1309f9e905804cea1e248a4572fed6b464b diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index d7266c0f56e0e..3671fdd3fd2be 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -165,7 +165,7 @@ target | std | notes `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA) `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA) `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23) -`sparcv9-sun-solaris` | ✓ | SPARC Solaris 10/11, illumos +`sparcv9-sun-solaris` | ✓ | SPARC Solaris 11, illumos `thumbv6m-none-eabi` | * | Bare ARMv6-M `thumbv7em-none-eabi` | * | Bare ARMv7E-M `thumbv7em-none-eabihf` | * | Bare ARMV7E-M, hardfloat @@ -184,7 +184,7 @@ target | std | notes `x86_64-fuchsia` | ✓ | Alias for `x86_64-unknown-fuchsia` [`x86_64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | 64-bit x86 Fuchsia [`x86_64-linux-android`](platform-support/android.md) | ✓ | 64-bit x86 Android -`x86_64-pc-solaris` | ✓ | 64-bit Solaris 10/11, illumos +`x86_64-pc-solaris` | ✓ | 64-bit Solaris 11, illumos `x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27) [`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | Freestanding/bare-metal x86_64, softfloat `x86_64-unknown-redox` | ✓ | Redox OS @@ -342,7 +342,6 @@ target | std | host | notes [`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS | [`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | `x86_64-pc-windows-msvc` | * | | 64-bit Windows XP support -`x86_64-sun-solaris` | ? | | Deprecated target for 64-bit Solaris 10/11, illumos [`x86_64-unikraft-linux-musl`](platform-support/unikraft-linux-musl.md) | ✓ | | 64-bit Unikraft with musl `x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD `x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 215ffc771f3da..83c7ccc9edeb7 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -151,7 +151,6 @@ static TARGETS: &[&str] = &[ "x86_64-linux-android", "x86_64-pc-windows-gnu", "x86_64-pc-windows-msvc", - "x86_64-sun-solaris", "x86_64-pc-solaris", "x86_64-unikraft-linux-musl", "x86_64-unknown-freebsd", diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 67b48a3742da0..554a12909fc85 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -37,7 +37,7 @@ jobs: - name: Set the tag GC interval to 1 on linux if: runner.os == 'Linux' - run: echo "MIRIFLAGS=-Zmiri-tag-gc=1" >> $GITHUB_ENV + run: echo "MIRIFLAGS=-Zmiri-provenance-gc=1" >> $GITHUB_ENV # 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 diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index f90fd1f7fc54e..aa0b791bd05fd 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -411,10 +411,10 @@ to Miri failing to detect cases of undefined behavior in a program. without an explicit value), `none` means it never recurses, `scalar` means it only recurses for types where we would also emit `noalias` annotations in the generated LLVM IR (types passed as individual scalars or pairs of scalars). Setting this to `none` is **unsound**. -* `-Zmiri-tag-gc=` configures how often the pointer tag garbage collector runs. The default - is to search for and remove unreachable tags once every `10000` basic blocks. Setting this to - `0` disables the garbage collector, which causes some programs to have explosive memory usage - and/or super-linear runtime. +* `-Zmiri-provenance-gc=` configures how often the pointer provenance garbage collector runs. + The default is to search for and remove unreachable provenance once every `10000` basic blocks. Setting + this to `0` disables the garbage collector, which causes some programs to have explosive memory + usage and/or super-linear runtime. * `-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/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 7f777cd4727ad..4517de6289319 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -531,10 +531,10 @@ 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=") { + } else if let Some(param) = arg.strip_prefix("-Zmiri-provenance-gc=") { let interval = match param.parse::() { Ok(i) => i, - Err(err) => show_error!("-Zmiri-tag-gc requires a `u32`: {}", err), + Err(err) => show_error!("-Zmiri-provenance-gc requires a `u32`: {}", err), }; miri_config.gc_interval = interval; } else if let Some(param) = arg.strip_prefix("-Zmiri-measureme=") { diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index f9cc3acbd51bc..8fae526922943 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -75,8 +75,8 @@ pub struct FrameState { protected_tags: SmallVec<[(AllocId, BorTag); 2]>, } -impl VisitTags for FrameState { - fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for FrameState { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { // `protected_tags` are already recorded by `GlobalStateInner`. } } @@ -110,10 +110,10 @@ pub struct GlobalStateInner { unique_is_unique: bool, } -impl VisitTags for GlobalStateInner { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for GlobalStateInner { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { for &tag in self.protected_tags.keys() { - visit(tag); + visit(None, Some(tag)); } // The only other candidate is base_ptr_tags, and that does not need visiting since we don't ever // GC the bottommost/root tag. @@ -236,6 +236,10 @@ impl GlobalStateInner { tag }) } + + pub fn remove_unreachable_allocs(&mut self, allocs: &LiveAllocs<'_, '_, '_>) { + self.base_ptr_tags.retain(|id, _| allocs.is_live(*id)); + } } /// Which borrow tracking method to use @@ -503,11 +507,11 @@ impl AllocState { } } -impl VisitTags for AllocState { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for AllocState { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { match self { - AllocState::StackedBorrows(sb) => sb.visit_tags(visit), - AllocState::TreeBorrows(tb) => tb.visit_tags(visit), + AllocState::StackedBorrows(sb) => sb.visit_provenance(visit), + AllocState::TreeBorrows(tb) => tb.visit_provenance(visit), } } } diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index a74c69d52f236..91d924976f78f 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -462,10 +462,10 @@ impl Stacks { } } -impl VisitTags for Stacks { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for Stacks { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { for tag in self.exposed_tags.iter().copied() { - visit(tag); + visit(None, Some(tag)); } } } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs index b3001b5b88cdc..43e6616e34a71 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs @@ -200,7 +200,7 @@ impl<'tcx> Tree { /// Climb the tree to get the tag of a distant ancestor. /// Allows operations on tags that are unreachable by the program /// but still exist in the tree. Not guaranteed to perform consistently - /// if `tag-gc=1`. + /// if `provenance-gc=1`. fn nth_parent(&self, tag: BorTag, nth_parent: u8) -> Option { let mut idx = self.tag_mapping.get(&tag).unwrap(); for _ in 0..nth_parent { diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index 4232cd396c95e..6801397b2cec6 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -742,11 +742,11 @@ impl Tree { } } -impl VisitTags for Tree { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for Tree { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { // To ensure that the root never gets removed, we visit it // (the `root` node of `Tree` is not an `Option<_>`) - visit(self.nodes.get(self.root).unwrap().tag) + visit(None, Some(self.nodes.get(self.root).unwrap().tag)) } } diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 5d109a7d55cef..80d0402fc8758 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -790,9 +790,9 @@ pub struct VClockAlloc { alloc_ranges: RefCell>, } -impl VisitTags for VClockAlloc { - fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) { - // No tags here. +impl VisitProvenance for VClockAlloc { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { + // No tags or allocIds here. } } @@ -1404,8 +1404,8 @@ pub struct GlobalState { pub track_outdated_loads: bool, } -impl VisitTags for GlobalState { - fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for GlobalState { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { // We don't have any tags. } } diff --git a/src/tools/miri/src/concurrency/init_once.rs b/src/tools/miri/src/concurrency/init_once.rs index 71582c75eae57..9a848d50341a4 100644 --- a/src/tools/miri/src/concurrency/init_once.rs +++ b/src/tools/miri/src/concurrency/init_once.rs @@ -45,10 +45,10 @@ pub(super) struct InitOnce<'mir, 'tcx> { data_race: VClock, } -impl<'mir, 'tcx> VisitTags for InitOnce<'mir, 'tcx> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl<'mir, 'tcx> VisitProvenance for InitOnce<'mir, 'tcx> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { for waiter in self.waiters.iter() { - waiter.callback.visit_tags(visit); + waiter.callback.visit_provenance(visit); } } } diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index 62f6d57ef36e1..b288b69e0cef9 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -181,10 +181,10 @@ pub(crate) struct SynchronizationState<'mir, 'tcx> { pub(super) init_onces: IndexVec>, } -impl<'mir, 'tcx> VisitTags for SynchronizationState<'mir, 'tcx> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl<'mir, 'tcx> VisitProvenance for SynchronizationState<'mir, 'tcx> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { for init_once in self.init_onces.iter() { - init_once.visit_tags(visit); + init_once.visit_provenance(visit); } } } diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 6449ed29cf8f7..754cfa4d2a827 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -43,7 +43,7 @@ pub enum TlsAllocAction { } /// Trait for callbacks that can be executed when some event happens, such as after a timeout. -pub trait MachineCallback<'mir, 'tcx>: VisitTags { +pub trait MachineCallback<'mir, 'tcx>: VisitProvenance { fn call(&self, ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>) -> InterpResult<'tcx>; } @@ -228,8 +228,8 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { } } -impl VisitTags for Thread<'_, '_> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for Thread<'_, '_> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let Thread { panic_payloads: panic_payload, last_error, @@ -242,17 +242,17 @@ impl VisitTags for Thread<'_, '_> { } = self; for payload in panic_payload { - payload.visit_tags(visit); + payload.visit_provenance(visit); } - last_error.visit_tags(visit); + last_error.visit_provenance(visit); for frame in stack { - frame.visit_tags(visit) + frame.visit_provenance(visit) } } } -impl VisitTags for Frame<'_, '_, Provenance, FrameExtra<'_>> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for Frame<'_, '_, Provenance, FrameExtra<'_>> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let Frame { return_place, locals, @@ -266,22 +266,22 @@ impl VisitTags for Frame<'_, '_, Provenance, FrameExtra<'_>> { } = self; // Return place. - return_place.visit_tags(visit); + return_place.visit_provenance(visit); // Locals. for local in locals.iter() { match local.as_mplace_or_imm() { None => {} Some(Either::Left((ptr, meta))) => { - ptr.visit_tags(visit); - meta.visit_tags(visit); + ptr.visit_provenance(visit); + meta.visit_provenance(visit); } Some(Either::Right(imm)) => { - imm.visit_tags(visit); + imm.visit_provenance(visit); } } } - extra.visit_tags(visit); + extra.visit_provenance(visit); } } @@ -341,8 +341,8 @@ pub struct ThreadManager<'mir, 'tcx> { timeout_callbacks: FxHashMap>, } -impl VisitTags for ThreadManager<'_, '_> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for ThreadManager<'_, '_> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let ThreadManager { threads, thread_local_alloc_ids, @@ -353,15 +353,15 @@ impl VisitTags for ThreadManager<'_, '_> { } = self; for thread in threads { - thread.visit_tags(visit); + thread.visit_provenance(visit); } for ptr in thread_local_alloc_ids.borrow().values() { - ptr.visit_tags(visit); + ptr.visit_provenance(visit); } for callback in timeout_callbacks.values() { - callback.callback.visit_tags(visit); + callback.callback.visit_provenance(visit); } - sync.visit_tags(visit); + sync.visit_provenance(visit); } } diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index 2ff344bb1a35f..39e89ce7faa7a 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -108,15 +108,15 @@ pub struct StoreBufferAlloc { store_buffers: RefCell>, } -impl VisitTags for StoreBufferAlloc { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for StoreBufferAlloc { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let Self { store_buffers } = self; for val in store_buffers .borrow() .iter() .flat_map(|buf| buf.buffer.iter().map(|element| &element.val)) { - val.visit_tags(visit); + val.visit_provenance(visit); } } } diff --git a/src/tools/miri/src/intptrcast.rs b/src/tools/miri/src/intptrcast.rs index 9966ee3fd919e..cd4d1bcc4647c 100644 --- a/src/tools/miri/src/intptrcast.rs +++ b/src/tools/miri/src/intptrcast.rs @@ -46,9 +46,21 @@ pub struct GlobalStateInner { provenance_mode: ProvenanceMode, } -impl VisitTags for GlobalStateInner { - fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) { - // Nothing to visit here. +impl VisitProvenance for GlobalStateInner { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { + let GlobalStateInner { + int_to_ptr_map: _, + base_addr: _, + exposed: _, + next_base_addr: _, + provenance_mode: _, + } = self; + // Though base_addr, int_to_ptr_map, and exposed contain AllocIds, we do not want to visit them. + // int_to_ptr_map and exposed must contain only live allocations, and those + // are never garbage collected. + // base_addr is only relevant if we have a pointer to an AllocId and need to look up its + // base address; so if an AllocId is not reachable from somewhere else we can remove it + // here. } } @@ -62,6 +74,12 @@ impl GlobalStateInner { provenance_mode: config.provenance_mode, } } + + pub fn remove_unreachable_allocs(&mut self, allocs: &LiveAllocs<'_, '_, '_>) { + // `exposed` and `int_to_ptr_map` are cleared immediately when an allocation + // is freed, so `base_addr` is the only one we have to clean up based on the GC. + self.base_addr.retain(|id, _| allocs.is_live(*id)); + } } /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple @@ -107,7 +125,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // We only use this provenance if it has been exposed. if global_state.exposed.contains(&alloc_id) { // This must still be live, since we remove allocations from `int_to_ptr_map` when they get freed. - debug_assert!(!matches!(ecx.get_alloc_info(alloc_id).2, AllocKind::Dead)); + debug_assert!(ecx.is_alloc_live(alloc_id)); Some(alloc_id) } else { None @@ -181,12 +199,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let ecx = self.eval_context_mut(); 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.borrow_tracker.is_some() { - ecx.expose_tag(alloc_id, tag)?; - } + if global_state.provenance_mode == ProvenanceMode::Strict { + return Ok(()); + } + // Exposing a dead alloc is a no-op, because it's not possible to get a dead allocation + // via int2ptr. + if !ecx.is_alloc_live(alloc_id) { + return Ok(()); + } + trace!("Exposing allocation id {alloc_id:?}"); + let global_state = ecx.machine.intptrcast.get_mut(); + global_state.exposed.insert(alloc_id); + if ecx.machine.borrow_tracker.is_some() { + ecx.expose_tag(alloc_id, tag)?; } Ok(()) } diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index b12aae6d4148c..119ec555b2e01 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -77,9 +77,9 @@ mod intptrcast; mod machine; mod mono_hash_map; mod operator; +mod provenance_gc; mod range_map; mod shims; -mod tag_gc; // Establish a "crate-wide prelude": we often import `crate::*`. @@ -125,8 +125,8 @@ pub use crate::machine::{ }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as _; +pub use crate::provenance_gc::{EvalContextExt as _, VisitProvenance, VisitWith, LiveAllocs}; pub use crate::range_map::RangeMap; -pub use crate::tag_gc::{EvalContextExt as _, VisitTags}; /// 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/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 2085df7d06f84..66d7dfcf3a108 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -77,12 +77,12 @@ impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> { } } -impl VisitTags for FrameExtra<'_> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for FrameExtra<'_> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _ } = self; - catch_unwind.visit_tags(visit); - borrow_tracker.visit_tags(visit); + catch_unwind.visit_provenance(visit); + borrow_tracker.visit_provenance(visit); } } @@ -311,13 +311,13 @@ pub struct AllocExtra<'tcx> { pub backtrace: Option>>, } -impl VisitTags for AllocExtra<'_> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for AllocExtra<'_> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let AllocExtra { borrow_tracker, data_race, weak_memory, backtrace: _ } = self; - borrow_tracker.visit_tags(visit); - data_race.visit_tags(visit); - weak_memory.visit_tags(visit); + borrow_tracker.visit_provenance(visit); + data_race.visit_provenance(visit); + weak_memory.visit_provenance(visit); } } @@ -793,8 +793,8 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { } } -impl VisitTags for MiriMachine<'_, '_> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for MiriMachine<'_, '_> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { #[rustfmt::skip] let MiriMachine { threads, @@ -843,20 +843,20 @@ impl VisitTags for MiriMachine<'_, '_> { allocation_spans: _, } = self; - threads.visit_tags(visit); - tls.visit_tags(visit); - env_vars.visit_tags(visit); - dir_handler.visit_tags(visit); - file_handler.visit_tags(visit); - data_race.visit_tags(visit); - borrow_tracker.visit_tags(visit); - intptrcast.visit_tags(visit); - main_fn_ret_place.visit_tags(visit); - argc.visit_tags(visit); - argv.visit_tags(visit); - cmd_line.visit_tags(visit); + threads.visit_provenance(visit); + tls.visit_provenance(visit); + env_vars.visit_provenance(visit); + dir_handler.visit_provenance(visit); + file_handler.visit_provenance(visit); + data_race.visit_provenance(visit); + borrow_tracker.visit_provenance(visit); + intptrcast.visit_provenance(visit); + main_fn_ret_place.visit_provenance(visit); + argc.visit_provenance(visit); + argv.visit_provenance(visit); + cmd_line.visit_provenance(visit); for ptr in extern_statics.values() { - ptr.visit_tags(visit); + ptr.visit_provenance(visit); } } } @@ -1380,7 +1380,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { // where it mistakenly removes an important tag become visible. if ecx.machine.gc_interval > 0 && ecx.machine.since_gc >= ecx.machine.gc_interval { ecx.machine.since_gc = 0; - ecx.garbage_collect_tags()?; + ecx.run_provenance_gc(); } // These are our preemption points. diff --git a/src/tools/miri/src/mono_hash_map.rs b/src/tools/miri/src/mono_hash_map.rs index 81b3153517f14..220233f8ff5f0 100644 --- a/src/tools/miri/src/mono_hash_map.rs +++ b/src/tools/miri/src/mono_hash_map.rs @@ -46,6 +46,14 @@ impl AllocMap for MonoHashMap { self.0.get_mut().contains_key(k) } + #[inline(always)] + fn contains_key_ref(&self, k: &Q) -> bool + where + K: Borrow, + { + self.0.borrow().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) diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs new file mode 100644 index 0000000000000..eac4aad27a0ca --- /dev/null +++ b/src/tools/miri/src/provenance_gc.rs @@ -0,0 +1,209 @@ +use either::Either; + +use rustc_data_structures::fx::FxHashSet; + +use crate::*; + +pub type VisitWith<'a> = dyn FnMut(Option, Option) + 'a; + +pub trait VisitProvenance { + fn visit_provenance(&self, visit: &mut VisitWith<'_>); +} + +impl VisitProvenance for Option { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + if let Some(x) = self { + x.visit_provenance(visit); + } + } +} + +impl VisitProvenance for std::cell::RefCell { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + self.borrow().visit_provenance(visit) + } +} + +impl VisitProvenance for BorTag { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + visit(None, Some(*self)) + } +} + +impl VisitProvenance for AllocId { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + visit(Some(*self), None) + } +} + +impl VisitProvenance for Provenance { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + if let Provenance::Concrete { alloc_id, tag, .. } = self { + visit(Some(*alloc_id), Some(*tag)); + } + } +} + +impl VisitProvenance for Pointer { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + let (prov, _offset) = self.into_parts(); + prov.visit_provenance(visit); + } +} + +impl VisitProvenance for Pointer> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + let (prov, _offset) = self.into_parts(); + prov.visit_provenance(visit); + } +} + +impl VisitProvenance for Scalar { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + match self { + Scalar::Ptr(ptr, _) => ptr.visit_provenance(visit), + Scalar::Int(_) => (), + } + } +} + +impl VisitProvenance for Immediate { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + match self { + Immediate::Scalar(s) => { + s.visit_provenance(visit); + } + Immediate::ScalarPair(s1, s2) => { + s1.visit_provenance(visit); + s2.visit_provenance(visit); + } + Immediate::Uninit => {} + } + } +} + +impl VisitProvenance for MemPlaceMeta { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + match self { + MemPlaceMeta::Meta(m) => m.visit_provenance(visit), + MemPlaceMeta::None => {} + } + } +} + +impl VisitProvenance for ImmTy<'_, Provenance> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + (**self).visit_provenance(visit) + } +} + +impl VisitProvenance for MPlaceTy<'_, Provenance> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + self.ptr().visit_provenance(visit); + self.meta().visit_provenance(visit); + } +} + +impl VisitProvenance for PlaceTy<'_, Provenance> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + match self.as_mplace_or_local() { + Either::Left(mplace) => mplace.visit_provenance(visit), + Either::Right(_) => (), + } + } +} + +impl VisitProvenance for OpTy<'_, Provenance> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + match self.as_mplace_or_imm() { + Either::Left(mplace) => mplace.visit_provenance(visit), + Either::Right(imm) => imm.visit_provenance(visit), + } + } +} + +impl VisitProvenance for Allocation> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + for prov in self.provenance().provenances() { + prov.visit_provenance(visit); + } + + self.extra.visit_provenance(visit); + } +} + +impl VisitProvenance for crate::MiriInterpCx<'_, '_> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + // Visit the contents of the allocations and the IDs themselves, to account for all + // live allocation IDs and all provenance in the allocation bytes, even if they are leaked. + // We do *not* visit all the `AllocId` of the live allocations; we tried that and adding + // them all to the live set is too expensive. Instead we later do liveness check by + // checking both "is this alloc id live" and "is it mentioned anywhere else in + // the interpreter state". + self.memory.alloc_map().iter(|it| { + for (_id, (_kind, alloc)) in it { + alloc.visit_provenance(visit); + } + }); + // And all the other machine values. + self.machine.visit_provenance(visit); + } +} + +pub struct LiveAllocs<'a, 'mir, 'tcx> { + collected: FxHashSet, + ecx: &'a MiriInterpCx<'mir, 'tcx>, +} + +impl LiveAllocs<'_, '_, '_> { + pub fn is_live(&self, id: AllocId) -> bool { + self.collected.contains(&id) || + self.ecx.is_alloc_live(id) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { + fn run_provenance_gc(&mut self) { + + // We collect all tags from various parts of the interpreter, but also + let this = self.eval_context_mut(); + + let mut tags = FxHashSet::default(); + let mut alloc_ids = FxHashSet::default(); + this.visit_provenance(&mut |id, tag| { + if let Some(id) = id { + alloc_ids.insert(id); + } + if let Some(tag) = tag { + tags.insert(tag); + } + }); + self.remove_unreachable_tags(tags); + self.remove_unreachable_allocs(alloc_ids); + } + + 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 { + if let Some(bt) = &alloc.extra.borrow_tracker { + bt.remove_unreachable_tags(&tags); + } + } + }); + } + + fn remove_unreachable_allocs(&mut self, allocs: FxHashSet) { + let this = self.eval_context_ref(); + let allocs = LiveAllocs { + ecx: this, + collected: allocs, + }; + this.machine.allocation_spans.borrow_mut().retain(|id, _| allocs.is_live(*id)); + this.machine.intptrcast.borrow_mut().remove_unreachable_allocs(&allocs); + if let Some(borrow_tracker) = &this.machine.borrow_tracker { + borrow_tracker.borrow_mut().remove_unreachable_allocs(&allocs); + } + } +} diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index 154a7f6983343..4243898590731 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -37,13 +37,13 @@ pub struct EnvVars<'tcx> { pub(crate) environ: Option>, } -impl VisitTags for EnvVars<'_> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for EnvVars<'_> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let EnvVars { map, environ } = self; - environ.visit_tags(visit); + environ.visit_provenance(visit); for ptr in map.values() { - ptr.visit_tags(visit); + ptr.visit_provenance(visit); } } } diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 329a30a9faf3b..d7aaa08dbf3fd 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -459,6 +459,10 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // shim, add it to the corresponding submodule. match link_name.as_str() { // Miri-specific extern functions + "miri_run_provenance_gc" => { + let [] = this.check_shim(abi, Abi::Rust, link_name, args)?; + this.run_provenance_gc(); + } "miri_get_alloc_id" => { let [ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 5c0f828e4e6bb..28652c25c2450 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -35,12 +35,12 @@ pub struct CatchUnwindData<'tcx> { ret: mir::BasicBlock, } -impl VisitTags for CatchUnwindData<'_> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for CatchUnwindData<'_> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let CatchUnwindData { catch_fn, data, dest, ret: _ } = self; - catch_fn.visit_tags(visit); - data.visit_tags(visit); - dest.visit_tags(visit); + catch_fn.visit_provenance(visit); + data.visit_provenance(visit); + dest.visit_provenance(visit); } } diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 4918698c6b277..792122a001676 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -274,8 +274,8 @@ struct UnblockCallback { thread_to_unblock: ThreadId, } -impl VisitTags for UnblockCallback { - fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) {} +impl VisitProvenance for UnblockCallback { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {} } impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for UnblockCallback { diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs index 62bd087e7e82d..b319516c25b9e 100644 --- a/src/tools/miri/src/shims/tls.rs +++ b/src/tools/miri/src/shims/tls.rs @@ -207,15 +207,15 @@ impl<'tcx> TlsData<'tcx> { } } -impl VisitTags for TlsData<'_> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for TlsData<'_> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let TlsData { keys, macos_thread_dtors, next_key: _ } = self; for scalar in keys.values().flat_map(|v| v.data.values()) { - scalar.visit_tags(visit); + scalar.visit_provenance(visit); } for (_, scalar) in macos_thread_dtors.values() { - scalar.visit_tags(visit); + scalar.visit_provenance(visit); } } } diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 062623a7f6a60..471eadb8c356f 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -288,8 +288,8 @@ pub struct FileHandler { pub handles: BTreeMap>, } -impl VisitTags for FileHandler { - fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for FileHandler { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { // All our FileDescriptor do not have any tags. } } @@ -490,12 +490,12 @@ impl Default for DirHandler { } } -impl VisitTags for DirHandler { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { +impl VisitProvenance for DirHandler { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let DirHandler { streams, next_id: _ } = self; for dir in streams.values() { - dir.entry.visit_tags(visit); + dir.entry.visit_provenance(visit); } } } diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index ff25b8120b1c0..10e06226b3fca 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -182,10 +182,10 @@ pub fn futex<'tcx>( dest: PlaceTy<'tcx, Provenance>, } - impl<'tcx> VisitTags for Callback<'tcx> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { + impl<'tcx> VisitProvenance for Callback<'tcx> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let Callback { thread: _, addr_usize: _, dest } = self; - dest.visit_tags(visit); + dest.visit_provenance(visit); } } diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs index 1a91219e01610..45b47450b7b2c 100644 --- a/src/tools/miri/src/shims/unix/sync.rs +++ b/src/tools/miri/src/shims/unix/sync.rs @@ -886,10 +886,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { dest: PlaceTy<'tcx, Provenance>, } - impl<'tcx> VisitTags for Callback<'tcx> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { + impl<'tcx> VisitProvenance for Callback<'tcx> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let Callback { active_thread: _, mutex_id: _, id: _, dest } = self; - dest.visit_tags(visit); + dest.visit_provenance(visit); } } diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs index 2c9603097c857..2b9801fea68e6 100644 --- a/src/tools/miri/src/shims/windows/sync.rs +++ b/src/tools/miri/src/shims/windows/sync.rs @@ -204,10 +204,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { pending_place: PlaceTy<'tcx, Provenance>, } - impl<'tcx> VisitTags for Callback<'tcx> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { + impl<'tcx> VisitProvenance for Callback<'tcx> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let Callback { init_once_id: _, pending_place } = self; - pending_place.visit_tags(visit); + pending_place.visit_provenance(visit); } } @@ -337,10 +337,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { dest: PlaceTy<'tcx, Provenance>, } - impl<'tcx> VisitTags for Callback<'tcx> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { + impl<'tcx> VisitProvenance for Callback<'tcx> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let Callback { thread: _, addr: _, dest } = self; - dest.visit_tags(visit); + dest.visit_provenance(visit); } } @@ -441,10 +441,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { dest: PlaceTy<'tcx, Provenance>, } - impl<'tcx> VisitTags for Callback<'tcx> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { + impl<'tcx> VisitProvenance for Callback<'tcx> { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let Callback { thread: _, condvar_id: _, lock_id: _, mode: _, dest } = self; - dest.visit_tags(visit); + dest.visit_provenance(visit); } } diff --git a/src/tools/miri/src/tag_gc.rs b/src/tools/miri/src/tag_gc.rs deleted file mode 100644 index 3cccdd3635388..0000000000000 --- a/src/tools/miri/src/tag_gc.rs +++ /dev/null @@ -1,169 +0,0 @@ -use either::Either; - -use rustc_data_structures::fx::FxHashSet; - -use crate::*; - -pub trait VisitTags { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)); -} - -impl VisitTags for Option { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - if let Some(x) = self { - x.visit_tags(visit); - } - } -} - -impl VisitTags for std::cell::RefCell { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - self.borrow().visit_tags(visit) - } -} - -impl VisitTags for BorTag { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - visit(*self) - } -} - -impl VisitTags for Provenance { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - if let Provenance::Concrete { tag, .. } = self { - visit(*tag); - } - } -} - -impl VisitTags for Pointer { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - let (prov, _offset) = self.into_parts(); - prov.visit_tags(visit); - } -} - -impl VisitTags for Pointer> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - let (prov, _offset) = self.into_parts(); - prov.visit_tags(visit); - } -} - -impl VisitTags for Scalar { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - match self { - Scalar::Ptr(ptr, _) => ptr.visit_tags(visit), - Scalar::Int(_) => (), - } - } -} - -impl VisitTags for Immediate { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - match self { - Immediate::Scalar(s) => { - s.visit_tags(visit); - } - Immediate::ScalarPair(s1, s2) => { - s1.visit_tags(visit); - s2.visit_tags(visit); - } - Immediate::Uninit => {} - } - } -} - -impl VisitTags for MemPlaceMeta { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - match self { - MemPlaceMeta::Meta(m) => m.visit_tags(visit), - MemPlaceMeta::None => {} - } - } -} - -impl VisitTags for ImmTy<'_, Provenance> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - (**self).visit_tags(visit) - } -} - -impl VisitTags for MPlaceTy<'_, Provenance> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - self.ptr().visit_tags(visit); - self.meta().visit_tags(visit); - } -} - -impl VisitTags for PlaceTy<'_, Provenance> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - match self.as_mplace_or_local() { - Either::Left(mplace) => mplace.visit_tags(visit), - Either::Right(_) => (), - } - } -} - -impl VisitTags for OpTy<'_, Provenance> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - match self.as_mplace_or_imm() { - Either::Left(mplace) => mplace.visit_tags(visit), - Either::Right(imm) => imm.visit_tags(visit), - } - } -} - -impl VisitTags for Allocation> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - for prov in self.provenance().provenances() { - prov.visit_tags(visit); - } - - self.extra.visit_tags(visit); - } -} - -impl VisitTags for crate::MiriInterpCx<'_, '_> { - fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) { - // Memory. - self.memory.alloc_map().iter(|it| { - for (_id, (_kind, alloc)) in it { - alloc.visit_tags(visit); - } - }); - - // And all the other machine values. - self.machine.visit_tags(visit); - } -} - -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'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.borrow_tracker.is_none() { - return Ok(()); - } - - let mut tags = FxHashSet::default(); - this.visit_tags(&mut |tag| { - tags.insert(tag); - }); - self.remove_unreachable_tags(tags); - - 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 { - if let Some(bt) = &alloc.extra.borrow_tracker { - bt.remove_unreachable_tags(&tags); - } - } - }); - } -} diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs index 465679b72c343..3769575765e95 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs +++ b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 +//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0 // Check how a Reserved with interior mutability // responds to a Foreign Write under a Protector diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.rs b/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.rs index 1e6e2eebd26ce..e2956759d0b36 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.rs +++ b/src/tools/miri/tests/fail/tree_borrows/reserved/int-protected-write.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 +//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0 #[path = "../../../utils/mod.rs"] #[macro_use] diff --git a/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs b/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs new file mode 100644 index 0000000000000..716119a0fc344 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs @@ -0,0 +1,21 @@ +//@ignore-target-windows: No libc on Windows +//@compile-flags: -Zmiri-permissive-provenance + +#[path = "../utils/mod.rs"] +mod utils; + +type GetEntropyFn = unsafe extern "C" fn(*mut u8, libc::size_t) -> libc::c_int; + +fn main() { + let name = "getentropy\0"; + let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) as usize }; + // If the GC does not account for the extra_fn_ptr entry that this dlsym just added, this GC + // run will delete our entry for the base addr of the function pointer we will transmute to, + // and the call through the function pointer will report UB. + utils::run_provenance_gc(); + + let ptr = addr as *mut libc::c_void; + let func: GetEntropyFn = unsafe { std::mem::transmute(ptr) }; + let dest = &mut [0u8]; + unsafe { func(dest.as_mut_ptr(), dest.len()) }; +} diff --git a/src/tools/miri/tests/pass/0weak_memory_consistency.rs b/src/tools/miri/tests/pass/0weak_memory_consistency.rs index abfe3b0adeb4d..1cbccb2eebdd8 100644 --- a/src/tools/miri/tests/pass/0weak_memory_consistency.rs +++ b/src/tools/miri/tests/pass/0weak_memory_consistency.rs @@ -1,4 +1,6 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows -Zmiri-provenance-gc=10000 +// This test's runtime explodes if the GC interval is set to 1 (which we do in CI), so we +// override it internally back to the default frequency. // The following tests check whether our weak memory emulation produces // any inconsistent execution outcomes diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs index 398b542ed4c24..e6310f8eda646 100644 --- a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs +++ b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 +//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0 #[path = "../../utils/mod.rs"] #[macro_use] mod utils; diff --git a/src/tools/miri/tests/pass/tree_borrows/end-of-protector.rs b/src/tools/miri/tests/pass/tree_borrows/end-of-protector.rs index fecc3360434d2..4d941850e5415 100644 --- a/src/tools/miri/tests/pass/tree_borrows/end-of-protector.rs +++ b/src/tools/miri/tests/pass/tree_borrows/end-of-protector.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 +//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0 // Check that a protector goes back to normal behavior when the function // returns. diff --git a/src/tools/miri/tests/pass/tree_borrows/formatting.rs b/src/tools/miri/tests/pass/tree_borrows/formatting.rs index f22c408ad2538..c4360f0dbb9a4 100644 --- a/src/tools/miri/tests/pass/tree_borrows/formatting.rs +++ b/src/tools/miri/tests/pass/tree_borrows/formatting.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 +//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0 #[path = "../../utils/mod.rs"] #[macro_use] diff --git a/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs b/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs index a38cd6d289416..7a5fd395c7fd8 100644 --- a/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs +++ b/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 +//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0 #[path = "../../utils/mod.rs"] #[macro_use] diff --git a/src/tools/miri/tests/pass/tree_borrows/reserved.rs b/src/tools/miri/tests/pass/tree_borrows/reserved.rs index 8d0beab66f406..ef47d30e2efca 100644 --- a/src/tools/miri/tests/pass/tree_borrows/reserved.rs +++ b/src/tools/miri/tests/pass/tree_borrows/reserved.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 +//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0 #[path = "../../utils/mod.rs"] #[macro_use] diff --git a/src/tools/miri/tests/pass/tree_borrows/unique.rs b/src/tools/miri/tests/pass/tree_borrows/unique.rs index 44e2e8136252e..6c5ed9efceeaa 100644 --- a/src/tools/miri/tests/pass/tree_borrows/unique.rs +++ b/src/tools/miri/tests/pass/tree_borrows/unique.rs @@ -1,5 +1,5 @@ //@revisions: default uniq -//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 +//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0 //@[uniq]compile-flags: -Zmiri-unique-is-unique #![feature(ptr_internals)] diff --git a/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs b/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs index e5d0a683a7237..8d0f4bd0fe79c 100644 --- a/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs +++ b/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs @@ -1,5 +1,5 @@ //@revisions: default uniq -//@compile-flags: -Zmiri-tree-borrows -Zmiri-tag-gc=0 +//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0 //@[uniq]compile-flags: -Zmiri-unique-is-unique #![feature(vec_into_raw_parts)] diff --git a/src/tools/miri/tests/utils/miri_extern.rs b/src/tools/miri/tests/utils/miri_extern.rs index c0ef2c506413d..7363c189840a8 100644 --- a/src/tools/miri/tests/utils/miri_extern.rs +++ b/src/tools/miri/tests/utils/miri_extern.rs @@ -84,7 +84,7 @@ extern "Rust" { /// /// The format of what this emits is unstable and may change at any time. In particular, users should be /// aware that Miri will periodically attempt to garbage collect the contents of all stacks. Callers of - /// this function may wish to pass `-Zmiri-tag-gc=0` to disable the GC. + /// this function may wish to pass `-Zmiri-provenance-gc=0` to disable the GC. /// /// This function is extremely unstable. At any time the format of its output may change, its signature may /// change, or it may be removed entirely. @@ -137,4 +137,9 @@ extern "Rust" { out: *mut std::ffi::c_char, out_size: usize, ) -> usize; + + /// Run the provenance GC. The GC will run automatically at some cadence, + /// but in tests we want to for sure run it at certain points to check + /// that it doesn't break anything. + pub fn miri_run_provenance_gc(); } diff --git a/src/tools/miri/tests/utils/mod.rs b/src/tools/miri/tests/utils/mod.rs index 7b7dc231a5019..6386162e09530 100644 --- a/src/tools/miri/tests/utils/mod.rs +++ b/src/tools/miri/tests/utils/mod.rs @@ -9,3 +9,10 @@ mod miri_extern; pub use fs::*; pub use miri_extern::*; + +pub fn run_provenance_gc() { + // SAFETY: No preconditions. The GC is fine to run at any time. + unsafe { + miri_run_provenance_gc() + } +} diff --git a/tests/assembly/stack-protector/stack-protector-target-support.rs b/tests/assembly/stack-protector/stack-protector-target-support.rs index c6528ac7c8d16..6d87fd1912b09 100644 --- a/tests/assembly/stack-protector/stack-protector-target-support.rs +++ b/tests/assembly/stack-protector/stack-protector-target-support.rs @@ -161,7 +161,7 @@ // [r77] needs-llvm-components: x86 // [r78] compile-flags:--target x86_64-linux-android // [r78] needs-llvm-components: x86 -// [r79] compile-flags:--target x86_64-sun-solaris +// [r79] compile-flags:--target x86_64-pc-solaris // [r79] needs-llvm-components: x86 // [r80] compile-flags:--target x86_64-unknown-freebsd // [r80] needs-llvm-components: x86