1
1
use std:: convert:: TryFrom ;
2
2
3
- use rustc:: ty:: { Ty , layout:: LayoutOf } ;
3
+ use rustc:: ty:: { Ty , layout:: { Size , LayoutOf } } ;
4
4
use rustc:: mir;
5
5
6
6
use crate :: * ;
7
7
8
8
pub trait EvalContextExt < ' tcx > {
9
- fn pointer_inbounds (
10
- & self ,
11
- ptr : Pointer < Tag >
12
- ) -> InterpResult < ' tcx > ;
13
-
14
9
fn binary_ptr_op (
15
10
& self ,
16
11
bin_op : mir:: BinOp ,
@@ -33,13 +28,6 @@ pub trait EvalContextExt<'tcx> {
33
28
}
34
29
35
30
impl < ' 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
-
43
31
fn binary_ptr_op (
44
32
& self ,
45
33
bin_op : mir:: BinOp ,
@@ -110,9 +98,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
110
98
}
111
99
112
100
/// 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.
116
103
fn pointer_offset_inbounds (
117
104
& self ,
118
105
ptr : Scalar < Tag > ,
@@ -123,25 +110,24 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
123
110
let offset = offset
124
111
. checked_mul ( pointee_size)
125
112
. 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 ( ) )
136
119
} 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 ( ) )
139
123
} ;
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)
146
132
}
147
133
}
0 commit comments