summary refs log tree commit diff
diff options
context:
space:
mode:
authorOli Scherer <github333195615777966@oli-obk.de>2025-07-10 14:55:07 +0000
committerOli Scherer <github333195615777966@oli-obk.de>2025-07-14 08:33:51 +0000
commiteef08a3f440967d72bf0e8ef8f3c7571abb64738 (patch)
tree30a77d20a9bbc45b0e450f93557460d94320b366
parentad635e5d0696076b4412dd7db7b7e8c0867d6e0c (diff)
downloadrust-eef08a3f440967d72bf0e8ef8f3c7571abb64738.tar.gz
rust-eef08a3f440967d72bf0e8ef8f3c7571abb64738.zip
Give all bytes of TypeId provenance
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs68
-rw-r--r--tests/ui/consts/const_transmute_type_id3.rs5
-rw-r--r--tests/ui/consts/const_transmute_type_id3.stderr4
-rw-r--r--tests/ui/consts/const_transmute_type_id5.rs21
-rw-r--r--tests/ui/consts/const_transmute_type_id5.stderr15
5 files changed, 79 insertions, 34 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 1eba1f2f03c..22d29eda913 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -44,17 +44,21 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         )?;
         self.copy_op_allow_transmute(&op, dest)?;
 
-        // Give the first pointer-size bytes provenance that knows about the type id.
+        // Give the each pointer-sized chunk provenance that knows about the type id.
         // Here we rely on `TypeId` being a newtype around an array of pointers, so we
-        // first project to its only field and then the first array element.
+        // first project to its only field and then the array elements.
         let alloc_id = tcx.reserve_and_set_type_id_alloc(ty);
         let first = self.project_field(dest, FieldIdx::ZERO)?;
-        let first = self.project_index(&first, 0)?;
-        let offset = self.read_scalar(&first)?.to_target_usize(&tcx)?;
-        let ptr = Pointer::new(alloc_id.into(), Size::from_bytes(offset));
-        let ptr = self.global_root_pointer(ptr)?;
-        let val = Scalar::from_pointer(ptr, &tcx);
-        self.write_scalar(val, &first)
+        let mut elem_iter = self.project_array_fields(&first)?;
+        while let Some((_, elem)) = elem_iter.next(self)? {
+            // Decorate this part of the hash with provenance; leave the integer part unchanged.
+            let hash_fragment = self.read_scalar(&elem)?.to_target_usize(&tcx)?;
+            let ptr = Pointer::new(alloc_id.into(), Size::from_bytes(hash_fragment));
+            let ptr = self.global_root_pointer(ptr)?;
+            let val = Scalar::from_pointer(ptr, &tcx);
+            self.write_scalar(val, &elem)?;
+        }
+        interp_ok(())
     }
 
     /// Returns `true` if emulation happened.
@@ -101,34 +105,36 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let mut a_fields = self.project_array_fields(&a_fields)?;
                 let mut b_fields = self.project_array_fields(&b_fields)?;
 
-                let (_idx, a) = a_fields
-                    .next(self)?
-                    .expect("we know the layout of TypeId has at least 2 array elements");
-                let a = self.deref_pointer(&a)?;
-                let (a, offset_a) = self.get_ptr_type_id(a.ptr())?;
-
-                let (_idx, b) = b_fields
-                    .next(self)?
-                    .expect("we know the layout of TypeId has at least 2 array elements");
-                let b = self.deref_pointer(&b)?;
-                let (b, offset_b) = self.get_ptr_type_id(b.ptr())?;
+                let mut provenance_a = None;
+                let mut provenance_b = None;
+                let mut provenance_matches = true;
 
-                let provenance_matches = a == b;
+                while let Some((i, a)) = a_fields.next(self)? {
+                    let (_, b) = b_fields.next(self)?.unwrap();
 
-                let mut eq_id = offset_a == offset_b;
+                    let a = self.deref_pointer(&a)?;
+                    let (a, offset_a) = self.get_ptr_type_id(a.ptr())?;
 
-                while let Some((_, a)) = a_fields.next(self)? {
-                    let (_, b) = b_fields.next(self)?.unwrap();
+                    let b = self.deref_pointer(&b)?;
+                    let (b, offset_b) = self.get_ptr_type_id(b.ptr())?;
 
-                    let a = self.read_target_usize(&a)?;
-                    let b = self.read_target_usize(&b)?;
-                    eq_id &= a == b;
-                }
+                    if *provenance_a.get_or_insert(a) != a {
+                        throw_ub_format!(
+                            "type_id_eq: the first TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's"
+                        )
+                    }
+                    if *provenance_b.get_or_insert(b) != b {
+                        throw_ub_format!(
+                            "type_id_eq: the second TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's"
+                        )
+                    }
+                    provenance_matches &= a == b;
 
-                if !eq_id && provenance_matches {
-                    throw_ub_format!(
-                        "type_id_eq: one of the TypeId arguments is invalid, the hash does not match the type it represents"
-                    )
+                    if offset_a != offset_b && provenance_matches {
+                        throw_ub_format!(
+                            "type_id_eq: one of the TypeId arguments is invalid, chunk {i} of the hash does not match the type it represents"
+                        )
+                    }
                 }
 
                 self.write_scalar(Scalar::from_bool(provenance_matches), dest)?;
diff --git a/tests/ui/consts/const_transmute_type_id3.rs b/tests/ui/consts/const_transmute_type_id3.rs
index ed5ff769701..f1bb8cddf77 100644
--- a/tests/ui/consts/const_transmute_type_id3.rs
+++ b/tests/ui/consts/const_transmute_type_id3.rs
@@ -1,3 +1,6 @@
+//! Test that all bytes of a TypeId must have the
+//! TypeId marker provenance.
+
 #![feature(const_type_id, const_trait_impl, const_cmp)]
 
 use std::any::TypeId;
@@ -10,7 +13,7 @@ const _: () = {
         std::ptr::write(ptr.offset(1), 999);
     }
     assert!(a == b);
-    //~^ ERROR: one of the TypeId arguments is invalid, the hash does not match the type it represents
+    //~^ ERROR: pointer must point to some allocation
 };
 
 fn main() {}
diff --git a/tests/ui/consts/const_transmute_type_id3.stderr b/tests/ui/consts/const_transmute_type_id3.stderr
index 8cfdcfebaa4..e731f496652 100644
--- a/tests/ui/consts/const_transmute_type_id3.stderr
+++ b/tests/ui/consts/const_transmute_type_id3.stderr
@@ -1,5 +1,5 @@
-error[E0080]: type_id_eq: one of the TypeId arguments is invalid, the hash does not match the type it represents
-  --> $DIR/const_transmute_type_id3.rs:12:13
+error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got 0x3e7[noalloc] which is a dangling pointer (it has no provenance)
+  --> $DIR/const_transmute_type_id3.rs:15:13
    |
 LL |     assert!(a == b);
    |             ^^^^^^ evaluation of `_` failed inside this call
diff --git a/tests/ui/consts/const_transmute_type_id5.rs b/tests/ui/consts/const_transmute_type_id5.rs
new file mode 100644
index 00000000000..0a9ba01e0dd
--- /dev/null
+++ b/tests/ui/consts/const_transmute_type_id5.rs
@@ -0,0 +1,21 @@
+//! Test that we require an equal TypeId to have the same integer
+//! part, even if the provenance matches.
+
+#![feature(const_type_id, const_trait_impl, const_cmp)]
+
+use std::any::TypeId;
+
+const _: () = {
+    let a = TypeId::of::<()>();
+    let mut b = TypeId::of::<()>();
+    unsafe {
+        let ptr = &mut b as *mut TypeId as *mut *const ();
+        // Copy the ptr at index 0 to index 1
+        let val = std::ptr::read(ptr);
+        std::ptr::write(ptr.offset(1), val);
+    }
+    assert!(a == b);
+    //~^ ERROR: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents
+};
+
+fn main() {}
diff --git a/tests/ui/consts/const_transmute_type_id5.stderr b/tests/ui/consts/const_transmute_type_id5.stderr
new file mode 100644
index 00000000000..59823fcc1c9
--- /dev/null
+++ b/tests/ui/consts/const_transmute_type_id5.stderr
@@ -0,0 +1,15 @@
+error[E0080]: type_id_eq: one of the TypeId arguments is invalid, chunk 1 of the hash does not match the type it represents
+  --> $DIR/const_transmute_type_id5.rs:17:13
+   |
+LL |     assert!(a == b);
+   |             ^^^^^^ evaluation of `_` failed inside this call
+   |
+note: inside `<TypeId as PartialEq>::eq`
+  --> $SRC_DIR/core/src/any.rs:LL:COL
+note: inside `<TypeId as PartialEq>::eq::compiletime`
+  --> $SRC_DIR/core/src/any.rs:LL:COL
+   = note: this error originates in the macro `$crate::intrinsics::const_eval_select` which comes from the expansion of the macro `crate::intrinsics::const_eval_select` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.