@@ -287,7 +287,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
287287
288288 /// Check if the pointer is "in-bounds". Notice that a pointer pointing at the end
289289 /// 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.
291295 pub fn check_bounds ( & self , ptr : Pointer , access : bool ) -> EvalResult < ' tcx > {
292296 let alloc = self . get ( ptr. alloc_id ) ?;
293297 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> {
498502
499503/// Byte accessors
500504impl < ' 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 (
503509 & self ,
504510 ptr : Pointer ,
505511 size : Size ,
506512 align : Align ,
513+ check_defined_and_ptr : bool ,
507514 ) -> 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`" ) ;
510516 self . check_align ( ptr. into ( ) , align) ?;
511- if size. bytes ( ) == 0 {
512- return Ok ( & [ ] ) ;
513- }
514517 // 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+
516527 let alloc = self . get ( ptr. alloc_id ) ?;
517528 assert_eq ! ( ptr. offset. bytes( ) as usize as u64 , ptr. offset. bytes( ) ) ;
518529 assert_eq ! ( size. bytes( ) as usize as u64 , size. bytes( ) ) ;
519530 let offset = ptr. offset . bytes ( ) as usize ;
520531 Ok ( & alloc. bytes [ offset..offset + size. bytes ( ) as usize ] )
521532 }
522533
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 (
525551 & mut self ,
526552 ptr : Pointer ,
527553 size : Size ,
528554 align : Align ,
529555 ) -> 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`" ) ;
532557 self . check_align ( ptr. into ( ) , align) ?;
533- if size. bytes ( ) == 0 {
534- return Ok ( & mut [ ] ) ;
535- }
536558 // 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+
538564 let alloc = self . get_mut ( ptr. alloc_id ) ?;
539565 assert_eq ! ( ptr. offset. bytes( ) as usize as u64 , ptr. offset. bytes( ) ) ;
540566 assert_eq ! ( size. bytes( ) as usize as u64 , size. bytes( ) ) ;
541567 let offset = ptr. offset . bytes ( ) as usize ;
542568 Ok ( & mut alloc. bytes [ offset..offset + size. bytes ( ) as usize ] )
543569 }
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- }
565570}
566571
567572/// Reading and writing
@@ -672,7 +677,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
672677 } ;
673678
674679 // 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 ( ) ;
676681 let dest_bytes = self . get_bytes_mut ( dest, size * length, dest_align) ?. as_mut_ptr ( ) ;
677682
678683 // 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> {
775780 // Make sure we don't read part of a pointer as a pointer
776781 self . check_relocation_edges ( ptr, size) ?;
777782 // 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+ ) ?;
779786 // Undef check happens *after* we established that the alignment is correct.
780787 // We must not return Ok() for unaligned pointers!
781788 if !self . is_defined ( ptr, size) ? {
0 commit comments