Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
88d314a
typeck enum discrs before attempting to compute layout
sjwang05 Jun 7, 2026
1bd00d4
Add support for -Zsanitizer-cfi-minimal-runtime
jakos-sec Sep 1, 2026
4d68be3
minor cleanup for minimal runtime test
jakos-sec Sep 10, 2026
855d8a2
Add target modifier for -Zsanitizer-cfi-minimal-runtime
jakos-sec Sep 10, 2026
a42ab2f
Make -Zsanitizer-cfi-minimal-runtime also dependent on -Zsanitizer=cfi
jakos-sec Sep 11, 2026
bba4a3f
Fix tests with new cfi-minimal-runtime target modifier
jakos-sec Sep 11, 2026
775c187
Fix linter issue in diagnostics.rs
jakos-sec Sep 11, 2026
3058339
Fix broken test introduced by cfi-minimal-runtime target modifier
jakos-sec Sep 11, 2026
7aacc8a
Skip gcc for CFI runtime tests
jakos-sec Sep 11, 2026
dddede5
Add regression test for hang on mutually recursive trait impls
zakrad Sep 21, 2026
8e5ad6c
use match to determine correct ubsan cfi handler
jakos-sec Sep 21, 2026
3285cce
fix `va_arg` on `f128` on `x86`
folkertdev Sep 19, 2026
20b6fd6
Address review feedback
jakos-sec Sep 23, 2026
caadd68
dont lower depth for coroutine witness and rigid opaques in auto trai…
adwinwhite Sep 4, 2026
ec51dae
Check the entire library and cg_clif workspaces for permitted deps in…
bjorn3 Apr 17, 2026
96b181c
tests: Run more pauth tests in CI and make them pass
jchlanda Sep 3, 2026
fc538ec
Add PermittedDeps type
bjorn3 Sep 24, 2026
288a941
add jank leak check test
lcnr Sep 24, 2026
db4d334
cleanup: clean up more dependencies that are unused
durin42 Sep 24, 2026
b28b83b
Rollup merge of #162228 - jchlanda:jakub/pac_span_test_fix, r=Enselic
jhpratt Sep 24, 2026
2119d32
Rollup merge of #162493 - jakos-sec:ubsan-runtime-minimal, r=rcvalle
jhpratt Sep 24, 2026
bd98321
Rollup merge of #163271 - lcnr:add-leak-check-test, r=lqd
jhpratt Sep 24, 2026
5179c93
Rollup merge of #163282 - durin42:moar-dep-cleanup, r=lqd
jhpratt Sep 24, 2026
f288e75
Rollup merge of #157562 - sjwang05:fix-138660-enum-discr-layout, r=Ki…
jhpratt Sep 24, 2026
c82a80e
Rollup merge of #162275 - adwinwhite:half-depth, r=lcnr
jhpratt Sep 24, 2026
b741aff
Rollup merge of #163037 - folkertdev:x86-vaarg-f128, r=beetrees
jhpratt Sep 24, 2026
bfe84c1
Rollup merge of #163114 - zakrad:regr-test-143018, r=camelid
jhpratt Sep 24, 2026
1e1df08
Rollup merge of #163255 - bjorn3:stricter_tidy_dep_check, r=clubby789
jhpratt Sep 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3440,7 +3440,6 @@ name = "replace-version-placeholder"
version = "0.1.0"
dependencies = [
"tidy",
"walkdir",
]

[[package]]
Expand Down
30 changes: 21 additions & 9 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2065,17 +2065,24 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
let is_diag = self.tcx.sess.opts.unstable_opts.sanitizer_cfi_diag.unwrap_or(false);
let is_recover =
self.tcx.sess.opts.unstable_opts.sanitizer_cfi_recover.unwrap_or(false);
let is_minimal =
self.tcx.sess.opts.unstable_opts.sanitizer_cfi_minimal_runtime.unwrap_or(false);

if is_diag || is_recover {
let fty = self.cx.type_func(
&[self.cx.type_ptr(), self.cx.type_isize(), self.cx.type_isize()],
self.cx.type_void(),
);
let fty = if is_minimal {
self.cx.type_func(&[], self.cx.type_void())
} else {
self.cx.type_func(
&[self.cx.type_ptr(), self.cx.type_isize(), self.cx.type_isize()],
self.cx.type_void(),
)
};
let ubsan_handler = self.declare_cfn(
if is_recover {
"__ubsan_handle_cfi_check_fail"
} else {
"__ubsan_handle_cfi_check_fail_abort"
match (is_minimal, is_recover) {
(true, true) => "__ubsan_handle_cfi_check_fail_minimal",
(true, false) => "__ubsan_handle_cfi_check_fail_minimal_abort",
(false, true) => "__ubsan_handle_cfi_check_fail",
(false, false) => "__ubsan_handle_cfi_check_fail_abort",
},
llvm::UnnamedAddr::Global,
fty,
Expand All @@ -2101,13 +2108,18 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
self.generate_ubsan_cfi_diag_data(self.span, expected_ty, check_kind);

let function_address = self.ptrtoint(llfn, self.cx.type_isize());
let arguments: &[_] = if is_minimal {
&[]
} else {
&[diag_data, function_address, self.const_usize(0)]
};
self.call(
fty,
None,
None,
ubsan_handler,
ReturnSlot::Direct,
&[diag_data, function_address, self.const_usize(0)],
arguments,
None,
None,
);
Expand Down
31 changes: 22 additions & 9 deletions compiler/rustc_codegen_llvm/src/va_arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1061,15 +1061,28 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
let stability = target.supports_c_variadic_definitions();

match target.arch {
Arch::X86 => emit_ptr_va_arg(
bx,
addr,
layout,
PassMode::Direct,
SlotSize::Bytes4,
if target.is_like_windows { AllowHigherAlign::No } else { AllowHigherAlign::Yes },
ForceRightAdjust::No,
),
Arch::X86 => {
// A small deviation from clang to get the right behavior for f128.
//
// Note that i64 and f64 have an alignment of only 4 on this architecture.
// We need to be careful when adding future types with an alignment bigger
// than 4 (e.g. i128), clang has a bunch of custom logic for them.
let allow_higher_align = if layout.ty == bx.tcx().types.f128 {
AllowHigherAlign::Yes
} else {
AllowHigherAlign::No
};

emit_ptr_va_arg(
bx,
addr,
layout,
PassMode::Direct,
SlotSize::Bytes4,
allow_higher_align,
ForceRightAdjust::No,
)
}
Arch::Arm64EC => emit_ptr_va_arg(
bx,
addr,
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1776,7 +1776,11 @@ fn add_sanitizer_libraries(
&& (sess.opts.unstable_opts.sanitizer_cfi_diag.unwrap_or(false)
|| sess.opts.unstable_opts.sanitizer_cfi_recover.unwrap_or(false))
{
link_sanitizer_runtime(sess, flavor, linker, "ubsan");
if sess.is_sanitizer_cfi_minimal_runtime_enabled() {
link_sanitizer_runtime(sess, flavor, linker, "ubsan_minimal");
} else {
link_sanitizer_runtime(sess, flavor, linker, "ubsan");
}
}
}

Expand Down
130 changes: 113 additions & 17 deletions compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -638,12 +638,119 @@ where
source: GoalSource,
goal: Goal<I, I::Predicate>,
) -> Result<GoalEvaluation<I>, NoSolutionOrRerunNonErased> {
let (normalization_nested_goals, goal_evaluation) =
self.evaluate_goal_raw(source, goal, LowerAvailableDepth::Yes)?;
let (normalization_nested_goals, goal_evaluation) = self.evaluate_goal_raw(source, goal)?;
assert!(normalization_nested_goals.is_empty());
Ok(goal_evaluation)
}

fn evaluate_in_search_graph(
&mut self,
canonical_goal: I::CanonicalInput,
step_kind: PathKind,
) -> (Result<CanonicalResponse<I>, NoSolution>, AccessedOpaques<I>) {
let increase_depth_for_nested =
match canonical_goal.canonical.value.goal.predicate.kind().skip_binder() {
// We don't lower the available depth for the `NormalizesTo` goal, as evaluating
// it is an extra step only exists in the new solver that behaves like a function
// call rather than an independent nested goal evaluation. So, decreasing the
// available depth may end up regressions which hit the recursion limits for crates
// compiled well with the old solver.
ty::PredicateKind::NormalizesTo(_) => LowerAvailableDepth::No,
// We also don't lower depth for witness and rigid opaque when proving auto traits.
// This is to mitigate the overflow FCW warnings in deeply nested async calls.
// See #159228.
//
// We're eventually going to remove the witness type so it's okay to ignore the
// depth.
// For rigid opaques, revealing hidden types can be viewed as normalization so it's
// consistent with the `NormalizesTo` reasoning above.
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
if self.cx().trait_is_auto(pred.trait_ref.def_id) {
match pred.self_ty().kind() {
ty::CoroutineWitness(..) => LowerAvailableDepth::No,
ty::Alias(
ty::IsRigid::Yes,
ty::AliasTy { kind: ty::Opaque { def_id, .. }, .. },
) => {
// We only want to skip lowering depth when the proving is done via
// auto trait leakage. If the goal can be proved via item bounds,
// we should lower depth faithfully.
//
// FIXME: We can have param env candidates via TAIT or RTN.
// Ideally we'd instead lower the depth for the nested goal instead.
// Implementing this is a bit harder.
if self
.cx()
.item_self_bounds(def_id.into())
.skip_binder()
.into_iter()
.any(|bound| {
bound
.as_trait_clause()
.is_some_and(|b| b.def_id() == pred.def_id())
})
{
LowerAvailableDepth::Yes
} else {
LowerAvailableDepth::No
}
}
ty::Bool
| ty::Char
| ty::Int(..)
| ty::Uint(..)
| ty::Float(..)
| ty::Str
| ty::Pat(..)
| ty::FnPtr(..)
| ty::Array(..)
| ty::Slice(..)
| ty::RawPtr(..)
| ty::Never
| ty::Tuple(..)
| ty::UnsafeBinder(_)
| ty::Param(..)
| ty::Placeholder(..)
| ty::Bound(..)
| ty::Infer(..)
| ty::Alias(_, _)
| ty::Ref(_, _, _)
| ty::Adt(_, _)
| ty::Foreign(_)
| ty::Dynamic(..)
| ty::Error(_)
| ty::FnDef(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..) => LowerAvailableDepth::Yes,
}
} else {
LowerAvailableDepth::Yes
}
}
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(_))
| ty::PredicateKind::Clause(ty::ClauseKind::Projection(_))
| ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_))
| ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_))
| ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(_, _))
| ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_))
| ty::PredicateKind::Subtype(_)
| ty::PredicateKind::Coerce(_)
| ty::PredicateKind::DynCompatible(_)
| ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_))
| ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(_))
| ty::PredicateKind::ConstEquate(_, _)
| ty::PredicateKind::Ambiguous => LowerAvailableDepth::Yes,
};
self.search_graph.evaluate_goal(
self.cx(),
canonical_goal,
step_kind,
increase_depth_for_nested,
&mut inspect::ProofTreeBuilder::new_noop(),
)
}

/// Recursively evaluates `goal`, returning the nested goals in case
/// the nested goal is a `NormalizesTo` goal.
///
Expand All @@ -655,7 +762,6 @@ where
&mut self,
source: GoalSource,
goal: Goal<I, I::Predicate>,
increase_depth_for_nested: LowerAvailableDepth,
) -> Result<(NestedNormalizationGoals<I>, GoalEvaluation<I>), NoSolutionOrRerunNonErased> {
// We only care about one entry per `OpaqueTypeKey` here,
// so we only canonicalize the lookup table and ignore
Expand Down Expand Up @@ -723,13 +829,8 @@ where
TypingMode::ErasedNotCoherence(MayBeErased),
);

let (canonical_result, accessed_opaques) = self.search_graph.evaluate_goal(
self.cx(),
canonical_goal,
step_kind,
increase_depth_for_nested,
&mut inspect::ProofTreeBuilder::new_noop(),
);
let (canonical_result, accessed_opaques) =
self.evaluate_in_search_graph(canonical_goal, step_kind);

let should_rerun = should_rerun_after_erased_canonicalization(
accessed_opaques,
Expand Down Expand Up @@ -763,13 +864,8 @@ where
let (orig_values, canonical_goal) =
canonicalize_goal(self.delegate, goal, &opaque_types, typing_mode);

let (canonical_result, accessed_opaques) = self.search_graph.evaluate_goal(
self.cx(),
canonical_goal,
step_kind,
increase_depth_for_nested,
&mut inspect::ProofTreeBuilder::new_noop(),
);
let (canonical_result, accessed_opaques) =
self.evaluate_in_search_graph(canonical_goal, step_kind);
assert!(
!accessed_opaques.might_rerun(),
"we run without TypingMode::ErasedNotCoherence, so opaques are available, and we don't retry if the outer typing mode is ErasedNotCoherence: {accessed_opaques:?} after {goal:?}"
Expand Down
12 changes: 1 addition & 11 deletions compiler/rustc_next_trait_solver/src/solve/project_goals/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ mod free_alias;
mod inherent;
mod opaque_types;

use rustc_type_ir::search_graph::LowerAvailableDepth;
use rustc_type_ir::solve::QueryResultOrRerunNonErased;
use rustc_type_ir::{self as ty, Interner, ProjectionClause};
use tracing::{instrument, trace};
Expand Down Expand Up @@ -70,16 +69,7 @@ where
let (
NestedNormalizationGoals(nested_goals),
GoalEvaluation { goal: _, certainty, stalled_on: _, has_changed: _ },
) = self.evaluate_goal_raw(
GoalSource::TypeRelating,
normalizes_to,
// We don't lower thr available depth for this `NormalizesTo` goal, as evaluating
// it is an extra step only exists in the new solver that behaves like a function
// call rather than an independent nested goal evaluation. So, decreasing the
// available depth may end up regressions which hit the recursion limits for crates
// compiled well with the old solver.
LowerAvailableDepth::No,
)?;
) = self.evaluate_goal_raw(GoalSource::TypeRelating, normalizes_to)?;

trace!(?nested_goals);

Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_session/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,16 @@ pub(crate) struct SanitizerCfiRecoverRequiresCfi;
#[diag("`-Zsanitizer-cfi-diag` requires `-Zsanitizer=cfi`")]
pub(crate) struct SanitizerCfiDiagRequiresCfi;

#[derive(Diagnostic)]
#[diag("`-Zsanitizer-cfi-minimal-runtime` requires `-Zsanitizer=cfi`")]
pub(crate) struct SanitizerCfiMinimalRuntimeRequiresCfi;

#[derive(Diagnostic)]
#[diag(
"`-Zsanitizer-cfi-minimal-runtime` requires `-Zsanitizer-cfi-recover` or `-Zsanitizer-cfi-diag`"
)]
pub(crate) struct SanitizerCfiMinimalRuntimeRequiresCfiRecoverOrDiag;

#[derive(Diagnostic)]
#[diag("`-Zsanitizer-kcfi-arity` requires `-Zsanitizer=kcfi`")]
pub(crate) struct SanitizerKcfiArityRequiresKcfi;
Expand Down
22 changes: 22 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,21 @@ mod target_modifier_consistency_check {
}
true
}
pub(super) fn sanitizer_cfi_minimal_runtime(
sess: &Session,
l: &TargetModifier,
r: Option<&TargetModifier>,
) -> bool {
// For CFI, the helper flag -Zsanitizer-cfi-minimal-runtime should also be a target modifier
if sess.sanitizers().contains(SanitizerSet::CFI) {
if let Some(r) = r {
return l.extend().tech_value == r.extend().tech_value;
} else {
return false;
}
}
true
}
pub(super) fn target_cpu(
sess: &Session,
l: &TargetModifier,
Expand Down Expand Up @@ -178,6 +193,11 @@ impl TargetModifier {
sess, self, other,
);
}
UnstableOptionsTargetModifiers::SanitizerCfiMinimalRuntime => {
return target_modifier_consistency_check::sanitizer_cfi_minimal_runtime(
sess, self, other,
);
}
_ => {}
},
OptionsTargetModifiers::CodegenOptions(codegen) => match codegen {
Expand Down Expand Up @@ -2825,6 +2845,8 @@ written to standard error output)"),
"enable CFI diagnostics (default: no)"),
sanitizer_cfi_recover: Option<bool> = (None, parse_opt_bool, [TRACKED],
"enable CFI recovery (default: no)"),
sanitizer_cfi_minimal_runtime: Option<bool> = (None, parse_opt_bool, [TRACKED] { TARGET_MODIFIER: SanitizerCfiMinimalRuntime },
"enable minimal UBSan runtime for CFI (default: no)"),
sanitizer_dataflow_abilist: Vec<String> = (Vec::new(), parse_comma_list, [TRACKED],
"additional ABI list files that control how shadow parameters are passed (comma separated)"),
sanitizer_kcfi_arity: Option<bool> = (None, parse_opt_bool, [TRACKED],
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,10 @@ impl Session {
self.opts.unstable_opts.sanitizer_cfi_diag == Some(true)
}

pub fn is_sanitizer_cfi_minimal_runtime_enabled(&self) -> bool {
self.opts.unstable_opts.sanitizer_cfi_minimal_runtime == Some(true)
}

pub fn is_sanitizer_kcfi_arity_enabled(&self) -> bool {
self.opts.unstable_opts.sanitizer_kcfi_arity == Some(true)
}
Expand Down Expand Up @@ -1683,6 +1687,16 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
}
}

// LLVM CFI minimal runtime requires CFI recovery or CFI diagnostics.
if sess.is_sanitizer_cfi_minimal_runtime_enabled() {
if !sess.is_sanitizer_cfi_enabled() {
sess.dcx().emit_err(diagnostics::SanitizerCfiMinimalRuntimeRequiresCfi);
} else if !(sess.is_sanitizer_cfi_recover_enabled() || sess.is_sanitizer_cfi_diag_enabled())
{
sess.dcx().emit_err(diagnostics::SanitizerCfiMinimalRuntimeRequiresCfiRecoverOrDiag);
}
}

// LLVM CFI integer normalization requires CFI or KCFI.
if sess.is_sanitizer_cfi_normalize_integers_enabled() {
if !(sess.is_sanitizer_cfi_enabled() || sess.is_sanitizer_kcfi_enabled()) {
Expand Down
Loading
Loading