@@ -287,7 +287,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
287
287
288
288
/// Check if the pointer is "in-bounds". Notice that a pointer pointing at the end
289
289
/// of an allocation (i.e., at the first *inaccessible* location) *is* considered
290
- /// in-bounds! This follows C's/LLVM's rules.
290
+ /// in-bounds! This follows C's/LLVM's rules. The `access` boolean is just used
291
+ /// for the error message.
292
+ /// If you want to check bounds before doing a memory access, be sure to
293
+ /// check the pointer one past the end of your access, then everything will
294
+ /// work out exactly.
291
295
pub fn check_bounds ( & self , ptr : Pointer , access : bool ) -> EvalResult < ' tcx > {
292
296
let alloc = self . get ( ptr. alloc_id ) ?;
293
297
let allocation_size = alloc. bytes . len ( ) as u64 ;
@@ -498,70 +502,71 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
498
502
499
503
/// Byte accessors
500
504
impl < ' a , ' mir , ' tcx , M : Machine < ' mir , ' tcx > > Memory < ' a , ' mir , ' tcx , M > {
501
- /// This checks alignment!
502
- fn get_bytes_unchecked (
505
+ /// The last argument controls whether we error out when there are undefined
506
+ /// or pointer bytes. You should never call this, call `get_bytes` or
507
+ /// `get_bytes_unchecked` instead,
508
+ fn get_bytes_internal (
503
509
& self ,
504
510
ptr : Pointer ,
505
511
size : Size ,
506
512
align : Align ,
513
+ check_defined_and_ptr : bool ,
507
514
) -> EvalResult < ' tcx , & [ u8 ] > {
508
- // Zero-sized accesses can use dangling pointers,
509
- // but they still have to be aligned and non-NULL
515
+ assert_ne ! ( size. bytes( ) , 0 , "0-sized accesses should never even get a `Pointer`" ) ;
510
516
self . check_align ( ptr. into ( ) , align) ?;
511
- if size. bytes ( ) == 0 {
512
- return Ok ( & [ ] ) ;
513
- }
514
517
// if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
515
- self . check_bounds ( ptr. offset ( size, self ) ?, true ) ?;
518
+ self . check_bounds ( ptr. offset ( size, & * self ) ?, true ) ?;
519
+
520
+ if check_defined_and_ptr {
521
+ self . check_defined ( ptr, size) ?;
522
+ if self . relocations ( ptr, size) ?. len ( ) != 0 {
523
+ return err ! ( ReadPointerAsBytes ) ;
524
+ }
525
+ }
526
+
516
527
let alloc = self . get ( ptr. alloc_id ) ?;
517
528
assert_eq ! ( ptr. offset. bytes( ) as usize as u64 , ptr. offset. bytes( ) ) ;
518
529
assert_eq ! ( size. bytes( ) as usize as u64 , size. bytes( ) ) ;
519
530
let offset = ptr. offset . bytes ( ) as usize ;
520
531
Ok ( & alloc. bytes [ offset..offset + size. bytes ( ) as usize ] )
521
532
}
522
533
523
- /// This checks alignment!
524
- fn get_bytes_unchecked_mut (
534
+ #[ inline]
535
+ fn get_bytes ( & self , ptr : Pointer , size : Size , align : Align ) -> EvalResult < ' tcx , & [ u8 ] > {
536
+ self . get_bytes_internal ( ptr, size, align, true )
537
+ }
538
+
539
+ /// It is the caller's responsibility to handle undefined and pointer bytes.
540
+ #[ inline]
541
+ fn get_bytes_with_undef_and_ptr (
542
+ & self ,
543
+ ptr : Pointer ,
544
+ size : Size ,
545
+ align : Align
546
+ ) -> EvalResult < ' tcx , & [ u8 ] > {
547
+ self . get_bytes_internal ( ptr, size, align, false )
548
+ }
549
+
550
+ fn get_bytes_mut (
525
551
& mut self ,
526
552
ptr : Pointer ,
527
553
size : Size ,
528
554
align : Align ,
529
555
) -> EvalResult < ' tcx , & mut [ u8 ] > {
530
- // Zero-sized accesses can use dangling pointers,
531
- // but they still have to be aligned and non-NULL
556
+ assert_ne ! ( size. bytes( ) , 0 , "0-sized accesses should never even get a `Pointer`" ) ;
532
557
self . check_align ( ptr. into ( ) , align) ?;
533
- if size. bytes ( ) == 0 {
534
- return Ok ( & mut [ ] ) ;
535
- }
536
558
// if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
537
- self . check_bounds ( ptr. offset ( size, & * self ) ?, true ) ?;
559
+ self . check_bounds ( ptr. offset ( size, & self ) ?, true ) ?;
560
+
561
+ self . mark_definedness ( ptr, size, true ) ?;
562
+ self . clear_relocations ( ptr, size) ?;
563
+
538
564
let alloc = self . get_mut ( ptr. alloc_id ) ?;
539
565
assert_eq ! ( ptr. offset. bytes( ) as usize as u64 , ptr. offset. bytes( ) ) ;
540
566
assert_eq ! ( size. bytes( ) as usize as u64 , size. bytes( ) ) ;
541
567
let offset = ptr. offset . bytes ( ) as usize ;
542
568
Ok ( & mut alloc. bytes [ offset..offset + size. bytes ( ) as usize ] )
543
569
}
544
-
545
- fn get_bytes ( & self , ptr : Pointer , size : Size , align : Align ) -> EvalResult < ' tcx , & [ u8 ] > {
546
- assert_ne ! ( size. bytes( ) , 0 ) ;
547
- if self . relocations ( ptr, size) ?. len ( ) != 0 {
548
- return err ! ( ReadPointerAsBytes ) ;
549
- }
550
- self . check_defined ( ptr, size) ?;
551
- self . get_bytes_unchecked ( ptr, size, align)
552
- }
553
-
554
- fn get_bytes_mut (
555
- & mut self ,
556
- ptr : Pointer ,
557
- size : Size ,
558
- align : Align ,
559
- ) -> EvalResult < ' tcx , & mut [ u8 ] > {
560
- assert_ne ! ( size. bytes( ) , 0 ) ;
561
- self . clear_relocations ( ptr, size) ?;
562
- self . mark_definedness ( ptr, size, true ) ?;
563
- self . get_bytes_unchecked_mut ( ptr, size, align)
564
- }
565
570
}
566
571
567
572
/// Reading and writing
@@ -672,7 +677,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
672
677
} ;
673
678
674
679
// This also checks alignment.
675
- let src_bytes = self . get_bytes_unchecked ( src, size, src_align) ?. as_ptr ( ) ;
680
+ let src_bytes = self . get_bytes_with_undef_and_ptr ( src, size, src_align) ?. as_ptr ( ) ;
676
681
let dest_bytes = self . get_bytes_mut ( dest, size * length, dest_align) ?. as_mut_ptr ( ) ;
677
682
678
683
// SAFE: The above indexing would have panicked if there weren't at least `size` bytes
@@ -775,7 +780,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
775
780
// Make sure we don't read part of a pointer as a pointer
776
781
self . check_relocation_edges ( ptr, size) ?;
777
782
// get_bytes_unchecked tests alignment
778
- let bytes = self . get_bytes_unchecked ( ptr, size, ptr_align. min ( self . int_align ( size) ) ) ?;
783
+ let bytes = self . get_bytes_with_undef_and_ptr (
784
+ ptr, size, ptr_align. min ( self . int_align ( size) )
785
+ ) ?;
779
786
// Undef check happens *after* we established that the alignment is correct.
780
787
// We must not return Ok() for unaligned pointers!
781
788
if !self . is_defined ( ptr, size) ? {
0 commit comments