diff options
| author | Matthew Maurer <mmaurer@google.com> | 2024-02-19 18:39:35 +0000 |
|---|---|---|
| committer | Matthew Maurer <mmaurer@google.com> | 2024-03-24 16:58:33 +0000 |
| commit | ea4518522f65480eb507a255dc215d39231e659f (patch) | |
| tree | c59ce29e34a6b0e7b36f91226025bed1e988b178 | |
| parent | 6a92312a1eaf5d9cffe3bdf9aaecbfdf8e2e35d9 (diff) | |
| download | rust-ea4518522f65480eb507a255dc215d39231e659f.tar.gz rust-ea4518522f65480eb507a255dc215d39231e659f.zip | |
CFI: Handle dyn with no principal
In user-facing Rust, `dyn` always has at least one predicate following it. Unfortunately, because we filter out marker traits from receivers at callsites and `dyn Sync` is, for example, legal, this results in us having `dyn` types with no predicates on occasion in our alias set encoding. This patch handles cases where there are no predicates in a `dyn` type which are relevant to its alias set. Fixes #122998
| -rw-r--r-- | compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs | 27 | ||||
| -rw-r--r-- | tests/ui/sanitizer/cfi-drop-no-principal.rs | 21 |
2 files changed, 35 insertions, 13 deletions
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 367fec0e8fc..eda7d396d72 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 @@ -747,9 +747,8 @@ fn transform_predicates<'tcx>( tcx: TyCtxt<'tcx>, predicates: &List<ty::PolyExistentialPredicate<'tcx>>, ) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>> { - let predicates: Vec<ty::PolyExistentialPredicate<'tcx>> = predicates - .iter() - .filter_map(|predicate| match predicate.skip_binder() { + tcx.mk_poly_existential_predicates_from_iter(predicates.iter().filter_map(|predicate| { + match predicate.skip_binder() { ty::ExistentialPredicate::Trait(trait_ref) => { let trait_ref = ty::TraitRef::identity(tcx, trait_ref.def_id); Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait( @@ -758,9 +757,8 @@ fn transform_predicates<'tcx>( } ty::ExistentialPredicate::Projection(..) => None, ty::ExistentialPredicate::AutoTrait(..) => Some(predicate), - }) - .collect(); - tcx.mk_poly_existential_predicates(&predicates) + } + })) } /// Transforms args for being encoded and used in the substitution dictionary. @@ -1171,14 +1169,17 @@ fn strip_receiver_auto<'tcx>( let ty::Dynamic(preds, lifetime, kind) = ty.kind() else { bug!("Tried to strip auto traits from non-dynamic type {ty}"); }; - let filtered_preds = - if preds.principal().is_some() { + let new_rcvr = if preds.principal().is_some() { + let filtered_preds = tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| { !matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..)) - })) - } else { - ty::List::empty() - }; - let new_rcvr = Ty::new_dynamic(tcx, filtered_preds, *lifetime, *kind); + })); + Ty::new_dynamic(tcx, filtered_preds, *lifetime, *kind) + } else { + // If there's no principal type, re-encode it as a unit, since we don't know anything + // about it. This technically discards the knowledge that it was a type that was made + // into a trait object at some point, but that's not a lot. + tcx.types.unit + }; tcx.mk_args_trait(new_rcvr, args.into_iter().skip(1)) } diff --git a/tests/ui/sanitizer/cfi-drop-no-principal.rs b/tests/ui/sanitizer/cfi-drop-no-principal.rs new file mode 100644 index 00000000000..c1c88c8c71c --- /dev/null +++ b/tests/ui/sanitizer/cfi-drop-no-principal.rs @@ -0,0 +1,21 @@ +// Check that dropping a trait object without a principal trait succeeds + +//@ needs-sanitizer-cfi +// FIXME(#122848) Remove only-linux once OSX CFI binaries works +//@ only-linux +//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi +//@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0 +// FIXME(#118761) Should be run-pass once the labels on drop are compatible. +// This test is being landed ahead of that to test that the compiler doesn't ICE while labeling the +// callsite for a drop, but the vtable doesn't have the correct label yet. +//@ build-pass + +struct CustomDrop; + +impl Drop for CustomDrop { + fn drop(&mut self) {} +} + +fn main() { + let _ = Box::new(CustomDrop) as Box<dyn Send>; +} |
