about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Maurer <mmaurer@google.com>2024-02-19 18:39:35 +0000
committerMatthew Maurer <mmaurer@google.com>2024-03-24 16:58:33 +0000
commitea4518522f65480eb507a255dc215d39231e659f (patch)
treec59ce29e34a6b0e7b36f91226025bed1e988b178
parent6a92312a1eaf5d9cffe3bdf9aaecbfdf8e2e35d9 (diff)
downloadrust-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.rs27
-rw-r--r--tests/ui/sanitizer/cfi-drop-no-principal.rs21
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>;
+}