33use std:: borrow:: Cow ;
44use std:: convert:: TryFrom ;
55use std:: iter;
6- use std:: ops:: { Deref , DerefMut , Range } ;
6+ use std:: ops:: { Deref , Range } ;
77use std:: ptr;
88
99use rustc_ast:: Mutability ;
@@ -25,7 +25,7 @@ use crate::ty;
2525/// module provides higher-level access.
2626#[ derive( Clone , Debug , Eq , PartialEq , PartialOrd , Ord , Hash , TyEncodable , TyDecodable ) ]
2727#[ derive( HashStable ) ]
28- pub struct Allocation < Tag = ( ) , Extra = ( ) > {
28+ pub struct Allocation < Tag = AllocId , Extra = ( ) > {
2929 /// The actual bytes of the allocation.
3030 /// Note that the bytes of a pointer represent the offset of the pointer.
3131 bytes : Vec < u8 > ,
@@ -154,26 +154,32 @@ impl<Tag> Allocation<Tag> {
154154 }
155155}
156156
157- impl Allocation < ( ) > {
158- /// Add Tag and Extra fields
159- pub fn with_tags_and_extra < T , E > (
157+ impl Allocation {
158+ /// Convert Tag and add Extra fields
159+ pub fn convert_tag_add_extra < Tag , Extra > (
160160 self ,
161- mut tagger : impl FnMut ( AllocId ) -> T ,
162- extra : E ,
163- ) -> Allocation < T , E > {
161+ cx : & impl HasDataLayout ,
162+ extra : Extra ,
163+ mut tagger : impl FnMut ( Pointer < AllocId > ) -> Pointer < Tag > ,
164+ ) -> Allocation < Tag , Extra > {
165+ // Compute new pointer tags, which also adjusts the bytes.
166+ let mut bytes = self . bytes ;
167+ let mut new_relocations = Vec :: with_capacity ( self . relocations . 0 . len ( ) ) ;
168+ let ptr_size = cx. data_layout ( ) . pointer_size . bytes_usize ( ) ;
169+ let endian = cx. data_layout ( ) . endian ;
170+ for & ( offset, alloc_id) in self . relocations . iter ( ) {
171+ let idx = offset. bytes_usize ( ) ;
172+ let ptr_bytes = & mut bytes[ idx..idx + ptr_size] ;
173+ let bits = read_target_uint ( endian, ptr_bytes) . unwrap ( ) ;
174+ let ( ptr_tag, ptr_offset) =
175+ tagger ( Pointer :: new ( alloc_id, Size :: from_bytes ( bits) ) ) . into_parts ( ) ;
176+ write_target_uint ( endian, ptr_bytes, ptr_offset. bytes ( ) . into ( ) ) . unwrap ( ) ;
177+ new_relocations. push ( ( offset, ptr_tag) ) ;
178+ }
179+ // Create allocation.
164180 Allocation {
165- bytes : self . bytes ,
166- relocations : Relocations :: from_presorted (
167- self . relocations
168- . iter ( )
169- // The allocations in the relocations (pointers stored *inside* this allocation)
170- // all get the base pointer tag.
171- . map ( |& ( offset, ( ( ) , alloc) ) | {
172- let tag = tagger ( alloc) ;
173- ( offset, ( tag, alloc) )
174- } )
175- . collect ( ) ,
176- ) ,
181+ bytes,
182+ relocations : Relocations :: from_presorted ( new_relocations) ,
177183 init_mask : self . init_mask ,
178184 align : self . align ,
179185 mutability : self . mutability ,
@@ -279,6 +285,9 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
279285 /// A raw pointer variant of `get_bytes_mut` that avoids invalidating existing aliases into this memory.
280286 pub fn get_bytes_mut_ptr ( & mut self , cx : & impl HasDataLayout , range : AllocRange ) -> * mut [ u8 ] {
281287 self . mark_init ( range, true ) ;
288+ // This also clears relocations that just overlap with the written range. So writing to some
289+ // byte can de-initialize its neighbors! See
290+ // <https://github.com/rust-lang/rust/issues/87184> for details.
282291 self . clear_relocations ( cx, range) ;
283292
284293 assert ! ( range. end( ) . bytes_usize( ) <= self . bytes. len( ) ) ; // need to do our own bounds-check
@@ -321,7 +330,11 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
321330 cx : & impl HasDataLayout ,
322331 range : AllocRange ,
323332 ) -> AllocResult < ScalarMaybeUninit < Tag > > {
324- // `get_bytes_unchecked` tests relocation edges.
333+ // `get_bytes_with_uninit_and_ptr` tests relocation edges.
334+ // We deliberately error when loading data that partially has provenance, or partially
335+ // initialized data (that's the check below), into a scalar. The LLVM semantics of this are
336+ // unclear so we are conservative. See <https://github.com/rust-lang/rust/issues/69488> for
337+ // further discussion.
325338 let bytes = self . get_bytes_with_uninit_and_ptr ( cx, range) ?;
326339 // Uninit check happens *after* we established that the alignment is correct.
327340 // We must not return `Ok()` for unaligned pointers!
@@ -339,9 +352,9 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
339352 self . check_relocations ( cx, range) ?;
340353 } else {
341354 // Maybe a pointer.
342- if let Some ( & ( tag , alloc_id ) ) = self . relocations . get ( & range. start ) {
343- let ptr = Pointer :: new_with_tag ( alloc_id , Size :: from_bytes ( bits) , tag ) ;
344- return Ok ( ScalarMaybeUninit :: Scalar ( ptr. into ( ) ) ) ;
355+ if let Some ( & prov ) = self . relocations . get ( & range. start ) {
356+ let ptr = Pointer :: new ( prov , Size :: from_bytes ( bits) ) ;
357+ return Ok ( ScalarMaybeUninit :: from_pointer ( ptr, cx ) ) ;
345358 }
346359 }
347360 // We don't. Just return the bits.
@@ -371,18 +384,23 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
371384 }
372385 } ;
373386
374- let bytes = match val. to_bits_or_ptr ( range. size , cx) {
375- Err ( val) => u128:: from ( val. offset . bytes ( ) ) ,
376- Ok ( data) => data,
387+ // `to_bits_or_ptr_internal` is the right method because we just want to store this data
388+ // as-is into memory.
389+ let ( bytes, provenance) = match val. to_bits_or_ptr_internal ( range. size ) {
390+ Err ( val) => {
391+ let ( provenance, offset) = val. into_parts ( ) ;
392+ ( u128:: from ( offset. bytes ( ) ) , Some ( provenance) )
393+ }
394+ Ok ( data) => ( data, None ) ,
377395 } ;
378396
379397 let endian = cx. data_layout ( ) . endian ;
380398 let dst = self . get_bytes_mut ( cx, range) ;
381399 write_target_uint ( endian, dst, bytes) . unwrap ( ) ;
382400
383401 // See if we have to also write a relocation.
384- if let Scalar :: Ptr ( val ) = val {
385- self . relocations . insert ( range. start , ( val . tag , val . alloc_id ) ) ;
402+ if let Some ( provenance ) = provenance {
403+ self . relocations . 0 . insert ( range. start , provenance ) ;
386404 }
387405
388406 Ok ( ( ) )
@@ -392,11 +410,7 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
392410/// Relocations.
393411impl < Tag : Copy , Extra > Allocation < Tag , Extra > {
394412 /// Returns all relocations overlapping with the given pointer-offset pair.
395- pub fn get_relocations (
396- & self ,
397- cx : & impl HasDataLayout ,
398- range : AllocRange ,
399- ) -> & [ ( Size , ( Tag , AllocId ) ) ] {
413+ pub fn get_relocations ( & self , cx : & impl HasDataLayout , range : AllocRange ) -> & [ ( Size , Tag ) ] {
400414 // We have to go back `pointer_size - 1` bytes, as that one would still overlap with
401415 // the beginning of this range.
402416 let start = range. start . bytes ( ) . saturating_sub ( cx. data_layout ( ) . pointer_size . bytes ( ) - 1 ) ;
@@ -446,7 +460,7 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
446460 }
447461
448462 // Forget all the relocations.
449- self . relocations . remove_range ( first..last) ;
463+ self . relocations . 0 . remove_range ( first..last) ;
450464 }
451465
452466 /// Errors if there are relocations overlapping with the edges of the
@@ -582,39 +596,33 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
582596 }
583597}
584598
585- /// Relocations.
599+ /// " Relocations" stores the provenance information of pointers stored in memory .
586600#[ derive( Clone , PartialEq , Eq , PartialOrd , Ord , Hash , Debug , TyEncodable , TyDecodable ) ]
587- pub struct Relocations < Tag = ( ) , Id = AllocId > ( SortedMap < Size , ( Tag , Id ) > ) ;
601+ pub struct Relocations < Tag = AllocId > ( SortedMap < Size , Tag > ) ;
588602
589- impl < Tag , Id > Relocations < Tag , Id > {
603+ impl < Tag > Relocations < Tag > {
590604 pub fn new ( ) -> Self {
591605 Relocations ( SortedMap :: new ( ) )
592606 }
593607
594608 // The caller must guarantee that the given relocations are already sorted
595609 // by address and contain no duplicates.
596- pub fn from_presorted ( r : Vec < ( Size , ( Tag , Id ) ) > ) -> Self {
610+ pub fn from_presorted ( r : Vec < ( Size , Tag ) > ) -> Self {
597611 Relocations ( SortedMap :: from_presorted_elements ( r) )
598612 }
599613}
600614
601615impl < Tag > Deref for Relocations < Tag > {
602- type Target = SortedMap < Size , ( Tag , AllocId ) > ;
616+ type Target = SortedMap < Size , Tag > ;
603617
604618 fn deref ( & self ) -> & Self :: Target {
605619 & self . 0
606620 }
607621}
608622
609- impl < Tag > DerefMut for Relocations < Tag > {
610- fn deref_mut ( & mut self ) -> & mut Self :: Target {
611- & mut self . 0
612- }
613- }
614-
615623/// A partial, owned list of relocations to transfer into another allocation.
616624pub struct AllocationRelocations < Tag > {
617- relative_relocations : Vec < ( Size , ( Tag , AllocId ) ) > ,
625+ relative_relocations : Vec < ( Size , Tag ) > ,
618626}
619627
620628impl < Tag : Copy , Extra > Allocation < Tag , Extra > {
@@ -652,7 +660,7 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
652660 /// The affected range, as defined in the parameters to `prepare_relocation_copy` is expected
653661 /// to be clear of relocations.
654662 pub fn mark_relocation_range ( & mut self , relocations : AllocationRelocations < Tag > ) {
655- self . relocations . insert_presorted ( relocations. relative_relocations ) ;
663+ self . relocations . 0 . insert_presorted ( relocations. relative_relocations ) ;
656664 }
657665}
658666
0 commit comments