@@ -504,7 +504,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
504
504
impl < ' a , ' mir , ' tcx , M : Machine < ' mir , ' tcx > > Memory < ' a , ' mir , ' tcx , M > {
505
505
/// The last argument controls whether we error out when there are undefined
506
506
/// 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,
508
508
fn get_bytes_internal (
509
509
& self ,
510
510
ptr : Pointer ,
@@ -519,9 +519,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
519
519
520
520
if check_defined_and_ptr {
521
521
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) ?;
525
526
}
526
527
527
528
let alloc = self . get ( ptr. alloc_id ) ?;
@@ -537,6 +538,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
537
538
}
538
539
539
540
/// 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.
540
542
#[ inline]
541
543
fn get_bytes_with_undef_and_ptr (
542
544
& self ,
@@ -547,6 +549,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
547
549
self . get_bytes_internal ( ptr, size, align, false )
548
550
}
549
551
552
+ /// Just calling this already marks everything as defined and removes relocations,
553
+ /// so be sure to actually put data there!
550
554
fn get_bytes_mut (
551
555
& mut self ,
552
556
ptr : Pointer ,
@@ -654,11 +658,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
654
658
}
655
659
let src = src. to_ptr ( ) ?;
656
660
let dest = dest. to_ptr ( ) ?;
657
- self . check_relocation_edges ( src, size) ?;
658
661
659
662
// first copy the relocations to a temporary buffer, because
660
663
// `get_bytes_mut` will clear the relocations, which is correct,
661
664
// 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).
662
667
let relocations = {
663
668
let relocations = self . relocations ( src, size) ?;
664
669
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> {
676
681
new_relocations
677
682
} ;
678
683
679
- // This also checks alignment.
684
+ // This also checks alignment, and relocation edges on the src .
680
685
let src_bytes = self . get_bytes_with_undef_and_ptr ( src, size, src_align) ?. as_ptr ( ) ;
681
686
let dest_bytes = self . get_bytes_mut ( dest, size * length, dest_align) ?. as_mut_ptr ( ) ;
682
687
@@ -710,8 +715,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
710
715
}
711
716
}
712
717
718
+ // copy definedness to the destination
713
719
self . copy_undef_mask ( src, dest, size, length) ?;
714
- // copy back the relocations
720
+ // copy the relocations to the destination
715
721
self . get_mut ( dest. alloc_id ) ?. relocations . insert_presorted ( relocations) ;
716
722
717
723
Ok ( ( ) )
@@ -724,9 +730,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
724
730
match alloc. bytes [ offset..] . iter ( ) . position ( |& c| c == 0 ) {
725
731
Some ( size) => {
726
732
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) ?;
730
734
self . check_defined ( ptr, p1) ?;
731
735
Ok ( & alloc. bytes [ offset..offset + size] )
732
736
}
@@ -777,9 +781,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
777
781
ptr_align : Align ,
778
782
size : Size
779
783
) -> 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
783
785
let bytes = self . get_bytes_with_undef_and_ptr (
784
786
ptr, size, ptr_align. min ( self . int_align ( size) )
785
787
) ?;
@@ -794,9 +796,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
794
796
let bits = read_target_uint ( self . tcx . data_layout . endian , bytes) . unwrap ( ) ;
795
797
// See if we got a pointer
796
798
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) ?;
800
801
} else {
801
802
let alloc = self . get ( ptr. alloc_id ) ?;
802
803
match alloc. relocations . get ( & ptr. offset ) {
@@ -887,16 +888,35 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
887
888
888
889
/// Relocations
889
890
impl < ' a , ' mir , ' tcx , M : Machine < ' mir , ' tcx > > Memory < ' a , ' mir , ' tcx , M > {
891
+ /// Return all relocations overlapping with the given ptr-offset pair.
890
892
fn relocations (
891
893
& self ,
892
894
ptr : Pointer ,
893
895
size : Size ,
894
896
) -> 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.
895
899
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
897
901
Ok ( self . get ( ptr. alloc_id ) ?. relocations . range ( Size :: from_bytes ( start) ..end) )
898
902
}
899
903
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.
900
920
fn clear_relocations ( & mut self , ptr : Pointer , size : Size ) -> EvalResult < ' tcx > {
901
921
// Find the start and end of the given range and its outermost relocations.
902
922
let ( first, last) = {
@@ -929,12 +949,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
929
949
Ok ( ( ) )
930
950
}
931
951
952
+ /// Error if there are relocations overlapping with the egdes of the
953
+ /// given memory range.
954
+ #[ inline]
932
955
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 ) ?;
938
958
Ok ( ( ) )
939
959
}
940
960
}
0 commit comments