@@ -6,44 +6,13 @@ use super::{
6
6
7
7
use crate :: ty:: layout:: { Size , Align } ;
8
8
use syntax:: ast:: Mutability ;
9
- use std:: { iter, fmt :: { self , Display } } ;
9
+ use std:: iter;
10
10
use crate :: mir;
11
- use std:: ops:: { Deref , DerefMut } ;
11
+ use std:: ops:: { Range , Deref , DerefMut } ;
12
12
use rustc_data_structures:: sorted_map:: SortedMap ;
13
- use rustc_macros:: HashStable ;
14
13
use rustc_target:: abi:: HasDataLayout ;
15
14
use std:: borrow:: Cow ;
16
15
17
- /// Used by `check_bounds` to indicate whether the pointer needs to be just inbounds
18
- /// or also inbounds of a *live* allocation.
19
- #[ derive( Debug , Copy , Clone , RustcEncodable , RustcDecodable , HashStable ) ]
20
- pub enum InboundsCheck {
21
- Live ,
22
- MaybeDead ,
23
- }
24
-
25
- /// Used by `check_in_alloc` to indicate context of check
26
- #[ derive( Debug , Copy , Clone , RustcEncodable , RustcDecodable , HashStable ) ]
27
- pub enum CheckInAllocMsg {
28
- MemoryAccessTest ,
29
- NullPointerTest ,
30
- PointerArithmeticTest ,
31
- InboundsTest ,
32
- }
33
-
34
- impl Display for CheckInAllocMsg {
35
- /// When this is printed as an error the context looks like this
36
- /// "{test name} failed: pointer must be in-bounds at offset..."
37
- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
38
- write ! ( f, "{}" , match * self {
39
- CheckInAllocMsg :: MemoryAccessTest => "Memory access" ,
40
- CheckInAllocMsg :: NullPointerTest => "Null pointer test" ,
41
- CheckInAllocMsg :: PointerArithmeticTest => "Pointer arithmetic" ,
42
- CheckInAllocMsg :: InboundsTest => "Inbounds test" ,
43
- } )
44
- }
45
- }
46
-
47
16
#[ derive( Clone , Debug , Eq , PartialEq , PartialOrd , Ord , Hash , RustcEncodable , RustcDecodable ) ]
48
17
pub struct Allocation < Tag =( ) , Extra =( ) > {
49
18
/// The actual bytes of the allocation.
@@ -146,54 +115,48 @@ impl<Tag> Allocation<Tag> {
146
115
147
116
impl < ' tcx > :: serialize:: UseSpecializedDecodable for & ' tcx Allocation { }
148
117
149
- /// Alignment and bounds checks
150
- impl < ' tcx , Tag , Extra > Allocation < Tag , Extra > {
151
- /// Checks if the pointer is "in-bounds". Notice that a pointer pointing at the end
152
- /// of an allocation (i.e., at the first *inaccessible* location) *is* considered
153
- /// in-bounds! This follows C's/LLVM's rules.
154
- /// If you want to check bounds before doing a memory access, better use `check_bounds`.
155
- fn check_bounds_ptr (
156
- & self ,
157
- ptr : Pointer < Tag > ,
158
- msg : CheckInAllocMsg ,
159
- ) -> InterpResult < ' tcx > {
160
- let allocation_size = self . bytes . len ( ) as u64 ;
161
- ptr. check_in_alloc ( Size :: from_bytes ( allocation_size) , msg)
162
- }
163
-
164
- /// Checks if the memory range beginning at `ptr` and of size `Size` is "in-bounds".
165
- #[ inline( always) ]
166
- pub fn check_bounds (
118
+ /// Byte accessors
119
+ impl < ' tcx , Tag : Copy , Extra : AllocationExtra < Tag > > Allocation < Tag , Extra > {
120
+ /// Just a small local helper function to avoid a bit of code repetition.
121
+ /// Returns the range of this allocation that was meant.
122
+ #[ inline]
123
+ fn check_bounds (
167
124
& self ,
168
- cx : & impl HasDataLayout ,
169
- ptr : Pointer < Tag > ,
170
- size : Size ,
171
- msg : CheckInAllocMsg ,
172
- ) -> InterpResult < ' tcx > {
173
- // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
174
- self . check_bounds_ptr ( ptr. offset ( size, cx) ?, msg)
125
+ offset : Size ,
126
+ size : Size
127
+ ) -> Range < usize > {
128
+ let end = offset + size; // this does overflow checking
129
+ assert_eq ! (
130
+ end. bytes( ) as usize as u64 , end. bytes( ) ,
131
+ "cannot handle this access on this host architecture"
132
+ ) ;
133
+ let end = end. bytes ( ) as usize ;
134
+ assert ! (
135
+ end <= self . bytes. len( ) ,
136
+ "Out-of-bounds access at offset {}, size {} in allocation of size {}" ,
137
+ offset. bytes( ) , size. bytes( ) , self . bytes. len( )
138
+ ) ;
139
+ ( offset. bytes ( ) as usize ) ..end
175
140
}
176
- }
177
141
178
- /// Byte accessors
179
- impl < ' tcx , Tag : Copy , Extra : AllocationExtra < Tag > > Allocation < Tag , Extra > {
180
142
/// The last argument controls whether we error out when there are undefined
181
143
/// or pointer bytes. You should never call this, call `get_bytes` or
182
144
/// `get_bytes_with_undef_and_ptr` instead,
183
145
///
184
146
/// This function also guarantees that the resulting pointer will remain stable
185
147
/// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies
186
148
/// on that.
149
+ ///
150
+ /// It is the caller's responsibility to check bounds and alignment beforehand.
187
151
fn get_bytes_internal (
188
152
& self ,
189
153
cx : & impl HasDataLayout ,
190
154
ptr : Pointer < Tag > ,
191
155
size : Size ,
192
156
check_defined_and_ptr : bool ,
193
- msg : CheckInAllocMsg ,
194
157
) -> InterpResult < ' tcx , & [ u8 ] >
195
158
{
196
- self . check_bounds ( cx , ptr, size, msg ) ? ;
159
+ let range = self . check_bounds ( ptr. offset , size) ;
197
160
198
161
if check_defined_and_ptr {
199
162
self . check_defined ( ptr, size) ?;
@@ -205,12 +168,13 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
205
168
206
169
AllocationExtra :: memory_read ( self , ptr, size) ?;
207
170
208
- assert_eq ! ( ptr. offset. bytes( ) as usize as u64 , ptr. offset. bytes( ) ) ;
209
- assert_eq ! ( size. bytes( ) as usize as u64 , size. bytes( ) ) ;
210
- let offset = ptr. offset . bytes ( ) as usize ;
211
- Ok ( & self . bytes [ offset..offset + size. bytes ( ) as usize ] )
171
+ Ok ( & self . bytes [ range] )
212
172
}
213
173
174
+ /// Check that these bytes are initialized and not pointer bytes, and then return them
175
+ /// as a slice.
176
+ ///
177
+ /// It is the caller's responsibility to check bounds and alignment beforehand.
214
178
#[ inline]
215
179
pub fn get_bytes (
216
180
& self ,
@@ -219,11 +183,13 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
219
183
size : Size ,
220
184
) -> InterpResult < ' tcx , & [ u8 ] >
221
185
{
222
- self . get_bytes_internal ( cx, ptr, size, true , CheckInAllocMsg :: MemoryAccessTest )
186
+ self . get_bytes_internal ( cx, ptr, size, true )
223
187
}
224
188
225
189
/// It is the caller's responsibility to handle undefined and pointer bytes.
226
190
/// However, this still checks that there are no relocations on the *edges*.
191
+ ///
192
+ /// It is the caller's responsibility to check bounds and alignment beforehand.
227
193
#[ inline]
228
194
pub fn get_bytes_with_undef_and_ptr (
229
195
& self ,
@@ -232,30 +198,28 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
232
198
size : Size ,
233
199
) -> InterpResult < ' tcx , & [ u8 ] >
234
200
{
235
- self . get_bytes_internal ( cx, ptr, size, false , CheckInAllocMsg :: MemoryAccessTest )
201
+ self . get_bytes_internal ( cx, ptr, size, false )
236
202
}
237
203
238
204
/// Just calling this already marks everything as defined and removes relocations,
239
205
/// so be sure to actually put data there!
206
+ ///
207
+ /// It is the caller's responsibility to check bounds and alignment beforehand.
240
208
pub fn get_bytes_mut (
241
209
& mut self ,
242
210
cx : & impl HasDataLayout ,
243
211
ptr : Pointer < Tag > ,
244
212
size : Size ,
245
213
) -> InterpResult < ' tcx , & mut [ u8 ] >
246
214
{
247
- assert_ne ! ( size. bytes( ) , 0 , "0-sized accesses should never even get a `Pointer`" ) ;
248
- self . check_bounds ( cx, ptr, size, CheckInAllocMsg :: MemoryAccessTest ) ?;
215
+ let range = self . check_bounds ( ptr. offset , size) ;
249
216
250
217
self . mark_definedness ( ptr, size, true ) ;
251
218
self . clear_relocations ( cx, ptr, size) ?;
252
219
253
220
AllocationExtra :: memory_written ( self , ptr, size) ?;
254
221
255
- assert_eq ! ( ptr. offset. bytes( ) as usize as u64 , ptr. offset. bytes( ) ) ;
256
- assert_eq ! ( size. bytes( ) as usize as u64 , size. bytes( ) ) ;
257
- let offset = ptr. offset . bytes ( ) as usize ;
258
- Ok ( & mut self . bytes [ offset..offset + size. bytes ( ) as usize ] )
222
+ Ok ( & mut self . bytes [ range] )
259
223
}
260
224
}
261
225
@@ -276,9 +240,10 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
276
240
let size_with_null = Size :: from_bytes ( ( size + 1 ) as u64 ) ;
277
241
// Go through `get_bytes` for checks and AllocationExtra hooks.
278
242
// We read the null, so we include it in the request, but we want it removed
279
- // from the result!
243
+ // from the result, so we do subslicing.
280
244
Ok ( & self . get_bytes ( cx, ptr, size_with_null) ?[ ..size] )
281
245
}
246
+ // This includes the case where `offset` is out-of-bounds to begin with.
282
247
None => err ! ( UnterminatedCString ( ptr. erase_tag( ) ) ) ,
283
248
}
284
249
}
@@ -306,7 +271,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
306
271
307
272
/// Writes `src` to the memory starting at `ptr.offset`.
308
273
///
309
- /// Will do bounds checks on the allocation .
274
+ /// It is the caller's responsibility to check bounds and alignment beforehand .
310
275
pub fn write_bytes (
311
276
& mut self ,
312
277
cx : & impl HasDataLayout ,
@@ -320,6 +285,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
320
285
}
321
286
322
287
/// Sets `count` bytes starting at `ptr.offset` with `val`. Basically `memset`.
288
+ ///
289
+ /// It is the caller's responsibility to check bounds and alignment beforehand.
323
290
pub fn write_repeat (
324
291
& mut self ,
325
292
cx : & impl HasDataLayout ,
@@ -342,7 +309,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
342
309
/// * in oder to obtain a `Pointer` we need to check for ZSTness anyway due to integer pointers
343
310
/// being valid for ZSTs
344
311
///
345
- /// Note: This function does not do *any* alignment checks, you need to do these before calling
312
+ /// It is the caller's responsibility to check bounds and alignment beforehand.
346
313
pub fn read_scalar (
347
314
& self ,
348
315
cx : & impl HasDataLayout ,
@@ -378,7 +345,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
378
345
Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: from_uint ( bits, size) ) )
379
346
}
380
347
381
- /// Note: This function does not do *any* alignment checks, you need to do these before calling
348
+ /// Read a pointer-sized scalar.
349
+ ///
350
+ /// It is the caller's responsibility to check bounds and alignment beforehand.
382
351
pub fn read_ptr_sized (
383
352
& self ,
384
353
cx : & impl HasDataLayout ,
@@ -395,7 +364,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
395
364
/// * in oder to obtain a `Pointer` we need to check for ZSTness anyway due to integer pointers
396
365
/// being valid for ZSTs
397
366
///
398
- /// Note: This function does not do *any* alignment checks, you need to do these before calling
367
+ /// It is the caller's responsibility to check bounds and alignment beforehand.
399
368
pub fn write_scalar (
400
369
& mut self ,
401
370
cx : & impl HasDataLayout ,
@@ -435,7 +404,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
435
404
Ok ( ( ) )
436
405
}
437
406
438
- /// Note: This function does not do *any* alignment checks, you need to do these before calling
407
+ /// Write a pointer-sized scalar.
408
+ ///
409
+ /// It is the caller's responsibility to check bounds and alignment beforehand.
439
410
pub fn write_ptr_sized (
440
411
& mut self ,
441
412
cx : & impl HasDataLayout ,
0 commit comments