From 70e1d23895f861ef6c3d936a91dd5f31e4ca0a40 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Mon, 25 Mar 2024 21:38:05 +0000 Subject: [PATCH] CFI: Pad out associated type resolution with erased lifetimes `trait_object_ty` assumed that associated types would be fully determined by the trait. This is *almost* true - const parameters and type parameters are no longer allowed, but lifetime parameters are. Since we erase all lifetime parameters anyways, instantiate it with as many erased regions as it needs. Fixes: #123053 --- .../src/typeid/typeid_itanium_cxx_abi.rs | 11 ++++-- .../cfi-assoc-ty-lifetime-issue-123053.rs | 38 +++++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 tests/ui/sanitizer/cfi-assoc-ty-lifetime-issue-123053.rs diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 3101015281b82..1c6a0f9cf4d4c 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -1124,7 +1124,10 @@ pub fn typeid_for_instance<'tcx>( .trait_item_def_id .expect("Part of a trait implementation, but not linked to the def_id?"); let trait_method = tcx.associated_item(method_id); - if traits::is_vtable_safe_method(tcx, trait_ref.skip_binder().def_id, trait_method) { + let trait_id = trait_ref.skip_binder().def_id; + if traits::is_vtable_safe_method(tcx, trait_id, trait_method) + && tcx.object_safety_violations(trait_id).is_empty() + { // Trait methods will have a Self polymorphic parameter, where the concreteized // implementatation will not. We need to walk back to the more general trait method let trait_ref = tcx.instantiate_and_normalize_erasing_regions( @@ -1152,8 +1155,8 @@ pub fn typeid_for_instance<'tcx>( let fn_abi = tcx .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty()))) - .unwrap_or_else(|instance| { - bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance) + .unwrap_or_else(|error| { + bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}") }); typeid_for_fnabi(tcx, fn_abi, options) @@ -1182,6 +1185,7 @@ fn strip_receiver_auto<'tcx>( tcx.mk_args_trait(new_rcvr, args.into_iter().skip(1)) } +#[instrument(skip(tcx), ret)] fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>) -> Ty<'tcx> { assert!(!poly_trait_ref.has_non_region_param()); let principal_pred = poly_trait_ref.map_bound(|trait_ref| { @@ -1199,6 +1203,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc ty::ParamEnv::reveal_all(), alias_ty.to_ty(tcx), ); + debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx)); ty::ExistentialPredicate::Projection(ty::ExistentialProjection { def_id: assoc_ty.def_id, args: ty::ExistentialTraitRef::erase_self_ty(tcx, super_trait_ref).args, diff --git a/tests/ui/sanitizer/cfi-assoc-ty-lifetime-issue-123053.rs b/tests/ui/sanitizer/cfi-assoc-ty-lifetime-issue-123053.rs new file mode 100644 index 0000000000000..dd604b6bf7dcd --- /dev/null +++ b/tests/ui/sanitizer/cfi-assoc-ty-lifetime-issue-123053.rs @@ -0,0 +1,38 @@ +// Regression test for issue 123053, where associated types with lifetimes caused generation of the +// trait object type to fail, causing an ICE. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi --edition=2021 +//@ no-prefer-dynamic +//@ only-x86_64-unknown-linux-gnu +//@ build-pass + +trait Iterable { + type Item<'a> + where + Self: 'a; + type Iter<'a>: Iterator> + where + Self: 'a; + + fn iter<'a>(&'a self) -> Self::Iter<'a>; +} + +impl Iterable for [T] { + type Item<'a> = as Iterator>::Item where T: 'a; + type Iter<'a> = std::slice::Iter<'a, T> where T: 'a; + + fn iter<'a>(&'a self) -> Self::Iter<'a> { + self.iter() + } +} + +fn get_first<'a, I: Iterable + ?Sized>(it: &'a I) -> Option> { + it.iter().next() +} + +fn main() { + let v = vec![1, 2, 3]; + + assert_eq!(Some(&1), get_first(&*v)); +}