@@ -504,7 +504,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
504504impl < ' a , ' mir , ' tcx , M : Machine < ' mir , ' tcx > > Memory < ' a , ' mir , ' tcx , M > {
505505 /// The last argument controls whether we error out when there are undefined
506506 /// or pointer bytes. You should never call this, call `get_bytes` or
507- /// `get_bytes_unchecked ` instead,
507+ /// `get_bytes_with_undef_and_ptr ` instead,
508508 fn get_bytes_internal (
509509 & self ,
510510 ptr : Pointer ,
@@ -519,9 +519,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
519519
520520 if check_defined_and_ptr {
521521 self . check_defined ( ptr, size) ?;
522- if self . relocations ( ptr, size) ?. len ( ) != 0 {
523- return err ! ( ReadPointerAsBytes ) ;
524- }
522+ self . check_relocations ( ptr, size) ?;
523+ } else {
524+ // We still don't want relocations on the *edges*
525+ self . check_relocation_edges ( ptr, size) ?;
525526 }
526527
527528 let alloc = self . get ( ptr. alloc_id ) ?;
@@ -537,6 +538,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
537538 }
538539
539540 /// It is the caller's responsibility to handle undefined and pointer bytes.
541+ /// However, this still checks that there are no relocations on the egdes.
540542 #[ inline]
541543 fn get_bytes_with_undef_and_ptr (
542544 & self ,
@@ -547,6 +549,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
547549 self . get_bytes_internal ( ptr, size, align, false )
548550 }
549551
552+ /// Just calling this already marks everything as defined and removes relocations,
553+ /// so be sure to actually put data there!
550554 fn get_bytes_mut (
551555 & mut self ,
552556 ptr : Pointer ,
@@ -654,11 +658,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
654658 }
655659 let src = src. to_ptr ( ) ?;
656660 let dest = dest. to_ptr ( ) ?;
657- self . check_relocation_edges ( src, size) ?;
658661
659662 // first copy the relocations to a temporary buffer, because
660663 // `get_bytes_mut` will clear the relocations, which is correct,
661664 // since we don't want to keep any relocations at the target.
665+ // (`get_bytes_with_undef_and_ptr` below checks that there are no
666+ // relocations overlapping the edges; those would not be handled correctly).
662667 let relocations = {
663668 let relocations = self . relocations ( src, size) ?;
664669 let mut new_relocations = Vec :: with_capacity ( relocations. len ( ) * ( length as usize ) ) ;
@@ -676,7 +681,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
676681 new_relocations
677682 } ;
678683
679- // This also checks alignment.
684+ // This also checks alignment, and relocation edges on the src .
680685 let src_bytes = self . get_bytes_with_undef_and_ptr ( src, size, src_align) ?. as_ptr ( ) ;
681686 let dest_bytes = self . get_bytes_mut ( dest, size * length, dest_align) ?. as_mut_ptr ( ) ;
682687
@@ -710,8 +715,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
710715 }
711716 }
712717
718+ // copy definedness to the destination
713719 self . copy_undef_mask ( src, dest, size, length) ?;
714- // copy back the relocations
720+ // copy the relocations to the destination
715721 self . get_mut ( dest. alloc_id ) ?. relocations . insert_presorted ( relocations) ;
716722
717723 Ok ( ( ) )
@@ -724,9 +730,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
724730 match alloc. bytes [ offset..] . iter ( ) . position ( |& c| c == 0 ) {
725731 Some ( size) => {
726732 let p1 = Size :: from_bytes ( ( size + 1 ) as u64 ) ;
727- if self . relocations ( ptr, p1) ?. len ( ) != 0 {
728- return err ! ( ReadPointerAsBytes ) ;
729- }
733+ self . check_relocations ( ptr, p1) ?;
730734 self . check_defined ( ptr, p1) ?;
731735 Ok ( & alloc. bytes [ offset..offset + size] )
732736 }
@@ -777,9 +781,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
777781 ptr_align : Align ,
778782 size : Size
779783 ) -> EvalResult < ' tcx , ScalarMaybeUndef > {
780- // Make sure we don't read part of a pointer as a pointer
781- self . check_relocation_edges ( ptr, size) ?;
782- // get_bytes_unchecked tests alignment
784+ // get_bytes_unchecked tests alignment and relocation edges
783785 let bytes = self . get_bytes_with_undef_and_ptr (
784786 ptr, size, ptr_align. min ( self . int_align ( size) )
785787 ) ?;
@@ -794,9 +796,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
794796 let bits = read_target_uint ( self . tcx . data_layout . endian , bytes) . unwrap ( ) ;
795797 // See if we got a pointer
796798 if size != self . pointer_size ( ) {
797- if self . relocations ( ptr, size) ?. len ( ) != 0 {
798- return err ! ( ReadPointerAsBytes ) ;
799- }
799+ // *Now* better make sure that the inside also is free of relocations.
800+ self . check_relocations ( ptr, size) ?;
800801 } else {
801802 let alloc = self . get ( ptr. alloc_id ) ?;
802803 match alloc. relocations . get ( & ptr. offset ) {
@@ -887,16 +888,35 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
887888
888889/// Relocations
889890impl < ' a , ' mir , ' tcx , M : Machine < ' mir , ' tcx > > Memory < ' a , ' mir , ' tcx , M > {
891+ /// Return all relocations overlapping with the given ptr-offset pair.
890892 fn relocations (
891893 & self ,
892894 ptr : Pointer ,
893895 size : Size ,
894896 ) -> EvalResult < ' tcx , & [ ( Size , AllocId ) ] > {
897+ // We have to go back `pointer_size - 1` bytes, as that one would still overlap with
898+ // the beginning of this range.
895899 let start = ptr. offset . bytes ( ) . saturating_sub ( self . pointer_size ( ) . bytes ( ) - 1 ) ;
896- let end = ptr. offset + size;
900+ let end = ptr. offset + size; // this does overflow checking
897901 Ok ( self . get ( ptr. alloc_id ) ?. relocations . range ( Size :: from_bytes ( start) ..end) )
898902 }
899903
904+ /// Check that there ar eno relocations overlapping with the given range.
905+ #[ inline( always) ]
906+ fn check_relocations ( & self , ptr : Pointer , size : Size ) -> EvalResult < ' tcx > {
907+ if self . relocations ( ptr, size) ?. len ( ) != 0 {
908+ err ! ( ReadPointerAsBytes )
909+ } else {
910+ Ok ( ( ) )
911+ }
912+ }
913+
914+ /// Remove all relocations inside the given range.
915+ /// If there are relocations overlapping with the edges, they
916+ /// are removed as well *and* the bytes they cover are marked as
917+ /// uninitialized. This is a somewhat odd "spooky action at a distance",
918+ /// but it allows strictly more code to run than if we would just error
919+ /// immediately in that case.
900920 fn clear_relocations ( & mut self , ptr : Pointer , size : Size ) -> EvalResult < ' tcx > {
901921 // Find the start and end of the given range and its outermost relocations.
902922 let ( first, last) = {
@@ -929,12 +949,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
929949 Ok ( ( ) )
930950 }
931951
952+ /// Error if there are relocations overlapping with the egdes of the
953+ /// given memory range.
954+ #[ inline]
932955 fn check_relocation_edges ( & self , ptr : Pointer , size : Size ) -> EvalResult < ' tcx > {
933- let overlapping_start = self . relocations ( ptr, Size :: ZERO ) ?. len ( ) ;
934- let overlapping_end = self . relocations ( ptr. offset ( size, self ) ?, Size :: ZERO ) ?. len ( ) ;
935- if overlapping_start + overlapping_end != 0 {
936- return err ! ( ReadPointerAsBytes ) ;
937- }
956+ self . check_relocations ( ptr, Size :: ZERO ) ?;
957+ self . check_relocations ( ptr. offset ( size, self ) ?, Size :: ZERO ) ?;
938958 Ok ( ( ) )
939959 }
940960}
0 commit comments