@@ -44,17 +44,21 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
4444 ) ?;
4545 self . copy_op_allow_transmute ( & op, dest) ?;
4646
47- // Give the first pointer-size bytes provenance that knows about the type id.
47+ // Give the each pointer-sized chunk provenance that knows about the type id.
4848 // Here we rely on `TypeId` being a newtype around an array of pointers, so we
49- // first project to its only field and then the first array element .
49+ // first project to its only field and then the array elements .
5050 let alloc_id = tcx. reserve_and_set_type_id_alloc ( ty) ;
5151 let first = self . project_field ( dest, FieldIdx :: ZERO ) ?;
52- let first = self . project_index ( & first, 0 ) ?;
53- let offset = self . read_scalar ( & first) ?. to_target_usize ( & tcx) ?;
54- let ptr = Pointer :: new ( alloc_id. into ( ) , Size :: from_bytes ( offset) ) ;
55- let ptr = self . global_root_pointer ( ptr) ?;
56- let val = Scalar :: from_pointer ( ptr, & tcx) ;
57- self . write_scalar ( val, & first)
52+ let mut elem_iter = self . project_array_fields ( & first) ?;
53+ while let Some ( ( _, elem) ) = elem_iter. next ( self ) ? {
54+ // Decorate this part of the hash with provenance; leave the integer part unchanged.
55+ let hash_fragment = self . read_scalar ( & elem) ?. to_target_usize ( & tcx) ?;
56+ let ptr = Pointer :: new ( alloc_id. into ( ) , Size :: from_bytes ( hash_fragment) ) ;
57+ let ptr = self . global_root_pointer ( ptr) ?;
58+ let val = Scalar :: from_pointer ( ptr, & tcx) ;
59+ self . write_scalar ( val, & elem) ?;
60+ }
61+ interp_ok ( ( ) )
5862 }
5963
6064 /// Returns `true` if emulation happened.
@@ -101,34 +105,36 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
101105 let mut a_fields = self . project_array_fields ( & a_fields) ?;
102106 let mut b_fields = self . project_array_fields ( & b_fields) ?;
103107
104- let ( _idx, a) = a_fields
105- . next ( self ) ?
106- . expect ( "we know the layout of TypeId has at least 2 array elements" ) ;
107- let a = self . deref_pointer ( & a) ?;
108- let ( a, offset_a) = self . get_ptr_type_id ( a. ptr ( ) ) ?;
109-
110- let ( _idx, b) = b_fields
111- . next ( self ) ?
112- . expect ( "we know the layout of TypeId has at least 2 array elements" ) ;
113- let b = self . deref_pointer ( & b) ?;
114- let ( b, offset_b) = self . get_ptr_type_id ( b. ptr ( ) ) ?;
108+ let mut provenance_a = None ;
109+ let mut provenance_b = None ;
110+ let mut provenance_matches = true ;
115111
116- let provenance_matches = a == b;
112+ while let Some ( ( i, a) ) = a_fields. next ( self ) ? {
113+ let ( _, b) = b_fields. next ( self ) ?. unwrap ( ) ;
117114
118- let mut eq_id = offset_a == offset_b;
115+ let a = self . deref_pointer ( & a) ?;
116+ let ( a, offset_a) = self . get_ptr_type_id ( a. ptr ( ) ) ?;
119117
120- while let Some ( ( _ , a ) ) = a_fields . next ( self ) ? {
121- let ( _ , b ) = b_fields . next ( self ) ? . unwrap ( ) ;
118+ let b = self . deref_pointer ( & b ) ? ;
119+ let ( b , offset_b ) = self . get_ptr_type_id ( b . ptr ( ) ) ? ;
122120
123- let a = self . read_target_usize ( & a) ?;
124- let b = self . read_target_usize ( & b) ?;
125- eq_id &= a == b;
126- }
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;
127132
128- if !eq_id && provenance_matches {
129- throw_ub_format ! (
130- "type_id_eq: one of the TypeId arguments is invalid, the hash does not match the type it represents"
131- )
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+ }
132138 }
133139
134140 self . write_scalar ( Scalar :: from_bool ( provenance_matches) , dest) ?;
0 commit comments