# UNDF: UNDF-2026-000000771 diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index c935869..9218cd1 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -1,9 +1,34 @@ +use rustc_data_structures::fx::FxHashSet; use rustc_macros::HashStable; use smallvec::SmallVec; use tracing::instrument; use crate::ty::{self, DefId, OpaqueTypeKey, Ty, TyCtxt, TypingEnv}; +/// Stack for cycle detection in `apply_inner`. +/// Wraps SmallVec (for push/pop LIFO order) with FxHashSet (for O(1) contains). +/// CWE-407 fix: SmallVec::contains is O(n); FxHashSet::contains is O(1). +#[derive(Default)] +struct EvalStack<'tcx> { + vec: SmallVec<[Ty<'tcx>; 1]>, + set: FxHashSet>, +} + +impl<'tcx> EvalStack<'tcx> { + fn contains(&self, t: &Ty<'tcx>) -> bool { + self.set.contains(t) + } + fn push(&mut self, t: Ty<'tcx>) { + self.vec.push(t); + self.set.insert(t); + } + fn pop(&mut self) { + if let Some(t) = self.vec.pop() { + self.set.remove(&t); + } + } +} + /// Represents whether some type is inhabited in a given context. /// Examples of uninhabited types are `!`, `enum Void {}`, or a struct /// containing either of those types. @@ -82,7 +107,7 @@ fn apply_inner( self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>, - eval_stack: &mut SmallVec<[Ty<'tcx>; 1]>, // for cycle detection + eval_stack: &mut EvalStack<'tcx>, // for cycle detection; Set-backed for O(1) contains in_module: &impl Fn(DefId) -> Result, reveal_opaque: &impl Fn(OpaqueTypeKey<'tcx>) -> Option>, ) -> Result { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index 8462471..713fec3 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -66,8 +66,10 @@ fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { vec = &mut self.blanket_impls; } + // CWE-407 partial fix: swap_remove is O(1) vs remove's O(n) shift. + // position() scan is still O(n); full O(1) requires Children to use IndexSet. let index = vec.iter().position(|d| *d == impl_def_id).unwrap(); - vec.remove(index); + vec.swap_remove(index); } /// Attempt to insert an impl into this set of children, while comparing for