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