Skip to content

Commit

Permalink
CFI: Pad out associated type resolution with erased lifetimes
Browse files Browse the repository at this point in the history
`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: rust-lang#123053
  • Loading branch information
maurer committed Apr 1, 2024
1 parent 4600c4a commit 8ff0228
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,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.normalize_erasing_regions(
Expand All @@ -1148,8 +1151,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)
Expand Down Expand Up @@ -1178,6 +1181,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| {
Expand All @@ -1195,6 +1199,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,
Expand Down
38 changes: 38 additions & 0 deletions tests/ui/sanitize/cfi-assoc-ty-lifetime-issue-123053.rs
Original file line number Diff line number Diff line change
@@ -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<Item = Self::Item<'a>>
where
Self: 'a;

fn iter<'a>(&'a self) -> Self::Iter<'a>;
}

impl<T> Iterable for [T] {
type Item<'a> = <std::slice::Iter<'a, T> 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<I::Item<'a>> {
it.iter().next()
}

fn main() {
let v = vec![1, 2, 3];

assert_eq!(Some(&1), get_first(&*v));
}

0 comments on commit 8ff0228

Please sign in to comment.