44
55use  std:: assert_matches:: assert_matches; 
66
7- use  rustc_abi:: { FieldIdx ,  Size } ; 
7+ use  rustc_abi:: { FieldIdx ,  HasDataLayout ,   Size } ; 
88use  rustc_apfloat:: ieee:: { Double ,  Half ,  Quad ,  Single } ; 
9+ use  rustc_middle:: mir:: interpret:: { read_target_uint,  write_target_uint} ; 
910use  rustc_middle:: mir:: { self ,  BinOp ,  ConstValue ,  NonDivergingIntrinsic } ; 
1011use  rustc_middle:: ty:: layout:: TyAndLayout ; 
1112use  rustc_middle:: ty:: { Ty ,  TyCtxt } ; 
@@ -30,7 +31,7 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll
3031} 
3132impl < ' tcx ,  M :  Machine < ' tcx > >  InterpCx < ' tcx ,  M >  { 
3233    /// Generates a value of `TypeId` for `ty` in-place. 
33- pub ( crate )   fn  write_type_id ( 
34+ fn  write_type_id ( 
3435        & mut  self , 
3536        ty :  Ty < ' tcx > , 
3637        dest :  & PlaceTy < ' tcx ,  M :: Provenance > , 
@@ -48,8 +49,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
4849        // Here we rely on `TypeId` being a newtype around an array of pointers, so we 
4950        // first project to its only field and then the array elements. 
5051        let  alloc_id = tcx. reserve_and_set_type_id_alloc ( ty) ; 
51-         let  first  = self . project_field ( dest,  FieldIdx :: ZERO ) ?; 
52-         let  mut  elem_iter = self . project_array_fields ( & first ) ?; 
52+         let  arr  = self . project_field ( dest,  FieldIdx :: ZERO ) ?; 
53+         let  mut  elem_iter = self . project_array_fields ( & arr ) ?; 
5354        while  let  Some ( ( _,  elem) )  = elem_iter. next ( self ) ? { 
5455            // Decorate this part of the hash with provenance; leave the integer part unchanged. 
5556            let  hash_fragment = self . read_scalar ( & elem) ?. to_target_usize ( & tcx) ?; 
@@ -61,6 +62,52 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
6162        interp_ok ( ( ) ) 
6263    } 
6364
65+     /// Read a value of type `TypeId`, returning the type it represents. 
66+ pub ( crate )  fn  read_type_id ( 
67+         & self , 
68+         op :  & OpTy < ' tcx ,  M :: Provenance > , 
69+     )  -> InterpResult < ' tcx ,  Ty < ' tcx > >  { 
70+         // `TypeId` is a newtype around an array of pointers. All pointers must have the same 
71+         // provenance, and that provenance represents the type. 
72+         let  ptr_size = self . pointer_size ( ) . bytes_usize ( ) ; 
73+         let  arr = self . project_field ( op,  FieldIdx :: ZERO ) ?; 
74+ 
75+         let  mut  ty_and_hash = None ; 
76+         let  mut  elem_iter = self . project_array_fields ( & arr) ?; 
77+         while  let  Some ( ( idx,  elem) )  = elem_iter. next ( self ) ? { 
78+             let  elem = self . read_pointer ( & elem) ?; 
79+             let  ( elem_ty,  elem_hash)  = self . get_ptr_type_id ( elem) ?; 
80+             // If this is the first element, remember the type and its hash. 
81+             // If this is not the first element, ensure it is consistent with the previous ones. 
82+             let  full_hash = match  ty_and_hash { 
83+                 None  => { 
84+                     let  hash = self . tcx . type_id_hash ( elem_ty) . as_u128 ( ) ; 
85+                     let  mut  hash_bytes = [ 0u8 ;  16 ] ; 
86+                     write_target_uint ( self . data_layout ( ) . endian ,  & mut  hash_bytes,  hash) . unwrap ( ) ; 
87+                     ty_and_hash = Some ( ( elem_ty,  hash_bytes) ) ; 
88+                     hash_bytes
89+                 } 
90+                 Some ( ( ty,  hash_bytes) )  => { 
91+                     if  ty != elem_ty { 
92+                         throw_ub_format ! ( 
93+                             "invalid `TypeId` value: not all bytes carry the same type id metadata" 
94+                         ) ; 
95+                     } 
96+                     hash_bytes
97+                 } 
98+             } ; 
99+             // Ensure the elem_hash matches the corresponding part of the full hash. 
100+             let  hash_frag = & full_hash[ ( idx as  usize )  *  ptr_size..] [ ..ptr_size] ; 
101+             if  read_target_uint ( self . data_layout ( ) . endian ,  hash_frag) . unwrap ( )  != elem_hash. into ( )  { 
102+                 throw_ub_format ! ( 
103+                     "invalid `TypeId` value: the hash does not match the type id metadata" 
104+                 ) ; 
105+             } 
106+         } 
107+ 
108+         interp_ok ( ty_and_hash. unwrap ( ) . 0 ) 
109+     } 
110+ 
64111    /// Returns `true` if emulation happened. 
65112/// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own 
66113/// intrinsic handling. 
@@ -97,47 +144,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
97144                self . write_type_id ( tp_ty,  dest) ?; 
98145            } 
99146            sym:: type_id_eq => { 
100-                 // Both operands are `TypeId`, which is a newtype around an array of pointers. 
101-                 // Project until we have the array elements. 
102-                 let  a_fields = self . project_field ( & args[ 0 ] ,  FieldIdx :: ZERO ) ?; 
103-                 let  b_fields = self . project_field ( & args[ 1 ] ,  FieldIdx :: ZERO ) ?; 
104- 
105-                 let  mut  a_fields = self . project_array_fields ( & a_fields) ?; 
106-                 let  mut  b_fields = self . project_array_fields ( & b_fields) ?; 
107- 
108-                 let  mut  provenance_a = None ; 
109-                 let  mut  provenance_b = None ; 
110-                 let  mut  provenance_matches = true ; 
111- 
112-                 while  let  Some ( ( i,  a) )  = a_fields. next ( self ) ? { 
113-                     let  ( _,  b)  = b_fields. next ( self ) ?. unwrap ( ) ; 
114- 
115-                     let  a = self . deref_pointer ( & a) ?; 
116-                     let  ( a,  offset_a)  = self . get_ptr_type_id ( a. ptr ( ) ) ?; 
117- 
118-                     let  b = self . deref_pointer ( & b) ?; 
119-                     let  ( b,  offset_b)  = self . get_ptr_type_id ( b. ptr ( ) ) ?; 
120- 
121-                     if  * provenance_a. get_or_insert ( a)  != a { 
122-                         throw_ub_format ! ( 
123-                             "type_id_eq: the first TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's" 
124-                         ) 
125-                     } 
126-                     if  * provenance_b. get_or_insert ( b)  != b { 
127-                         throw_ub_format ! ( 
128-                             "type_id_eq: the second TypeId argument is invalid, the provenance of chunk {i} does not match the first chunk's" 
129-                         ) 
130-                     } 
131-                     provenance_matches &= a == b; 
132- 
133-                     if  offset_a != offset_b && provenance_matches { 
134-                         throw_ub_format ! ( 
135-                             "type_id_eq: one of the TypeId arguments is invalid, chunk {i} of the hash does not match the type it represents" 
136-                         ) 
137-                     } 
138-                 } 
139- 
140-                 self . write_scalar ( Scalar :: from_bool ( provenance_matches) ,  dest) ?; 
147+                 let  a_ty = self . read_type_id ( & args[ 0 ] ) ?; 
148+                 let  b_ty = self . read_type_id ( & args[ 1 ] ) ?; 
149+                 self . write_scalar ( Scalar :: from_bool ( a_ty == b_ty) ,  dest) ?; 
141150            } 
142151            sym:: variant_count => { 
143152                let  tp_ty = instance. args . type_at ( 0 ) ; 
0 commit comments