11use std:: convert:: TryFrom ;
22
3- use rustc:: ty:: { Ty , layout:: LayoutOf } ;
3+ use rustc:: ty:: { Ty , layout:: { Size , LayoutOf } } ;
44use rustc:: mir;
55
66use crate :: * ;
77
88pub trait EvalContextExt < ' tcx > {
9- fn pointer_inbounds (
10- & self ,
11- ptr : Pointer < Tag >
12- ) -> InterpResult < ' tcx > ;
13-
149 fn binary_ptr_op (
1510 & self ,
1611 bin_op : mir:: BinOp ,
@@ -33,13 +28,6 @@ pub trait EvalContextExt<'tcx> {
3328}
3429
3530impl < ' mir , ' tcx > EvalContextExt < ' tcx > for super :: MiriEvalContext < ' mir , ' tcx > {
36- /// Test if the pointer is in-bounds of a live allocation.
37- #[ inline]
38- fn pointer_inbounds ( & self , ptr : Pointer < Tag > ) -> InterpResult < ' tcx > {
39- let ( size, _align) = self . memory . get_size_and_align ( ptr. alloc_id , AllocCheck :: Live ) ?;
40- ptr. check_inbounds_alloc ( size, CheckInAllocMsg :: InboundsTest )
41- }
42-
4331 fn binary_ptr_op (
4432 & self ,
4533 bin_op : mir:: BinOp ,
@@ -110,9 +98,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
11098 }
11199
112100 /// Raises an error if the offset moves the pointer outside of its allocation.
113- /// We consider ZSTs their own huge allocation that doesn't overlap with anything (and nothing
114- /// moves in there because the size is 0). We also consider the NULL pointer its own separate
115- /// allocation, and all the remaining integers pointers their own allocation.
101+ /// For integers, we consider each of them their own tiny allocation of size 0,
102+ /// so offset-by-0 is okay for them -- except for NULL, which we rule out entirely.
116103 fn pointer_offset_inbounds (
117104 & self ,
118105 ptr : Scalar < Tag > ,
@@ -123,25 +110,24 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
123110 let offset = offset
124111 . checked_mul ( pointee_size)
125112 . ok_or_else ( || err_panic ! ( Overflow ( mir:: BinOp :: Mul ) ) ) ?;
126- // Now let's see what kind of pointer this is.
127- let ptr = if offset == 0 {
128- match ptr {
129- Scalar :: Ptr ( ptr) => ptr,
130- Scalar :: Raw { .. } => {
131- // Offset 0 on an integer. We accept that, pretending there is
132- // a little zero-sized allocation here.
133- return Ok ( ptr) ;
134- }
135- }
113+ // We do this first, to rule out overflows.
114+ let offset_ptr = ptr. ptr_signed_offset ( offset, self ) ?;
115+ // What we need to check is that starting at `min(ptr, offset_ptr)`,
116+ // we could do an access of size `abs(offset)`. Alignment does not matter.
117+ let ( min_ptr, abs_offset) = if offset >= 0 {
118+ ( ptr, u64:: try_from ( offset) . unwrap ( ) )
136119 } else {
137- // Offset > 0. We *require* a pointer.
138- self . force_ptr ( ptr) ?
120+ // Negative offset.
121+ // If the negation overflows, the result will be negative so the try_from will fail.
122+ ( offset_ptr, u64:: try_from ( -offset) . unwrap ( ) )
139123 } ;
140- // Both old and new pointer must be in-bounds of a *live* allocation.
141- // (Of the same allocation, but that part is trivial with our representation.)
142- self . pointer_inbounds ( ptr) ?;
143- let ptr = ptr. signed_offset ( offset, self ) ?;
144- self . pointer_inbounds ( ptr) ?;
145- Ok ( Scalar :: Ptr ( ptr) )
124+ self . memory . check_ptr_access_align (
125+ min_ptr,
126+ Size :: from_bytes ( abs_offset) ,
127+ None ,
128+ CheckInAllocMsg :: InboundsTest ,
129+ ) ?;
130+ // That's it!
131+ Ok ( offset_ptr)
146132 }
147133}
0 commit comments