@@ -8,7 +8,7 @@ use crate::ty::layout::{Size, Align};
8
8
use syntax:: ast:: Mutability ;
9
9
use std:: { iter, fmt:: { self , Display } } ;
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
13
use rustc_macros:: HashStable ;
14
14
use rustc_target:: abi:: HasDataLayout ;
@@ -146,54 +146,48 @@ impl<Tag> Allocation<Tag> {
146
146
147
147
impl < ' tcx > :: serialize:: UseSpecializedDecodable for & ' tcx Allocation { }
148
148
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 (
149
+ /// Byte accessors
150
+ impl < ' tcx , Tag : Copy , Extra : AllocationExtra < Tag > > Allocation < Tag , Extra > {
151
+ /// Just a small local helper function to avoid a bit of code repetition.
152
+ /// Returns the range of this allocation that was meant.
153
+ #[ inline]
154
+ fn check_bounds (
156
155
& 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)
156
+ offset : Size ,
157
+ size : Size
158
+ ) -> Range < usize > {
159
+ let end = offset + size; // this does overflow checking
160
+ assert_eq ! (
161
+ end. bytes( ) as usize as u64 , end. bytes( ) ,
162
+ "cannot handle this access on this host architecture"
163
+ ) ;
164
+ let end = end. bytes ( ) as usize ;
165
+ assert ! (
166
+ end <= self . bytes. len( ) ,
167
+ "Out-of-bounds access at offset {}, size {} in allocation of size {}" ,
168
+ offset. bytes( ) , size. bytes( ) , self . bytes. len( )
169
+ ) ;
170
+ ( offset. bytes ( ) as usize ) ..end
162
171
}
163
172
164
- /// Checks if the memory range beginning at `ptr` and of size `Size` is "in-bounds".
165
- #[ inline( always) ]
166
- pub fn check_bounds (
167
- & 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)
175
- }
176
- }
177
-
178
- /// Byte accessors
179
- impl < ' tcx , Tag : Copy , Extra : AllocationExtra < Tag > > Allocation < Tag , Extra > {
180
173
/// The last argument controls whether we error out when there are undefined
181
174
/// or pointer bytes. You should never call this, call `get_bytes` or
182
175
/// `get_bytes_with_undef_and_ptr` instead,
183
176
///
184
177
/// This function also guarantees that the resulting pointer will remain stable
185
178
/// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies
186
179
/// on that.
180
+ ///
181
+ /// It is the callers responsibility to check bounds and alignment beforehand.
187
182
fn get_bytes_internal (
188
183
& self ,
189
184
cx : & impl HasDataLayout ,
190
185
ptr : Pointer < Tag > ,
191
186
size : Size ,
192
187
check_defined_and_ptr : bool ,
193
- msg : CheckInAllocMsg ,
194
188
) -> InterpResult < ' tcx , & [ u8 ] >
195
189
{
196
- self . check_bounds ( cx , ptr, size, msg ) ? ;
190
+ let range = self . check_bounds ( ptr. offset , size) ;
197
191
198
192
if check_defined_and_ptr {
199
193
self . check_defined ( ptr, size) ?;
@@ -205,12 +199,13 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
205
199
206
200
AllocationExtra :: memory_read ( self , ptr, size) ?;
207
201
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 ] )
202
+ Ok ( & self . bytes [ range] )
212
203
}
213
204
205
+ /// Check that these bytes are initialized and not pointer bytes, and then return them
206
+ /// as a slice.
207
+ ///
208
+ /// It is the callers responsibility to check bounds and alignment beforehand.
214
209
#[ inline]
215
210
pub fn get_bytes (
216
211
& self ,
@@ -219,11 +214,13 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
219
214
size : Size ,
220
215
) -> InterpResult < ' tcx , & [ u8 ] >
221
216
{
222
- self . get_bytes_internal ( cx, ptr, size, true , CheckInAllocMsg :: MemoryAccessTest )
217
+ self . get_bytes_internal ( cx, ptr, size, true )
223
218
}
224
219
225
220
/// It is the caller's responsibility to handle undefined and pointer bytes.
226
221
/// However, this still checks that there are no relocations on the *edges*.
222
+ ///
223
+ /// It is the callers responsibility to check bounds and alignment beforehand.
227
224
#[ inline]
228
225
pub fn get_bytes_with_undef_and_ptr (
229
226
& self ,
@@ -232,30 +229,28 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
232
229
size : Size ,
233
230
) -> InterpResult < ' tcx , & [ u8 ] >
234
231
{
235
- self . get_bytes_internal ( cx, ptr, size, false , CheckInAllocMsg :: MemoryAccessTest )
232
+ self . get_bytes_internal ( cx, ptr, size, false )
236
233
}
237
234
238
235
/// Just calling this already marks everything as defined and removes relocations,
239
236
/// so be sure to actually put data there!
237
+ ///
238
+ /// It is the callers responsibility to check bounds and alignment beforehand.
240
239
pub fn get_bytes_mut (
241
240
& mut self ,
242
241
cx : & impl HasDataLayout ,
243
242
ptr : Pointer < Tag > ,
244
243
size : Size ,
245
244
) -> InterpResult < ' tcx , & mut [ u8 ] >
246
245
{
247
- assert_ne ! ( size. bytes( ) , 0 , "0-sized accesses should never even get a `Pointer`" ) ;
248
- self . check_bounds ( cx, ptr, size, CheckInAllocMsg :: MemoryAccessTest ) ?;
246
+ let range = self . check_bounds ( ptr. offset , size) ;
249
247
250
248
self . mark_definedness ( ptr, size, true ) ;
251
249
self . clear_relocations ( cx, ptr, size) ?;
252
250
253
251
AllocationExtra :: memory_written ( self , ptr, size) ?;
254
252
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 ] )
253
+ Ok ( & mut self . bytes [ range] )
259
254
}
260
255
}
261
256
@@ -276,9 +271,10 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
276
271
let size_with_null = Size :: from_bytes ( ( size + 1 ) as u64 ) ;
277
272
// Go through `get_bytes` for checks and AllocationExtra hooks.
278
273
// We read the null, so we include it in the request, but we want it removed
279
- // from the result!
274
+ // from the result, so we do subslicing.
280
275
Ok ( & self . get_bytes ( cx, ptr, size_with_null) ?[ ..size] )
281
276
}
277
+ // This includes the case where `offset` is out-of-bounds to begin with.
282
278
None => err ! ( UnterminatedCString ( ptr. erase_tag( ) ) ) ,
283
279
}
284
280
}
@@ -306,7 +302,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
306
302
307
303
/// Writes `src` to the memory starting at `ptr.offset`.
308
304
///
309
- /// Will do bounds checks on the allocation .
305
+ /// It is the callers responsibility to check bounds and alignment beforehand .
310
306
pub fn write_bytes (
311
307
& mut self ,
312
308
cx : & impl HasDataLayout ,
@@ -320,6 +316,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
320
316
}
321
317
322
318
/// Sets `count` bytes starting at `ptr.offset` with `val`. Basically `memset`.
319
+ ///
320
+ /// It is the callers responsibility to check bounds and alignment beforehand.
323
321
pub fn write_repeat (
324
322
& mut self ,
325
323
cx : & impl HasDataLayout ,
@@ -342,7 +340,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
342
340
/// * in oder to obtain a `Pointer` we need to check for ZSTness anyway due to integer pointers
343
341
/// being valid for ZSTs
344
342
///
345
- /// Note: This function does not do *any* alignment checks, you need to do these before calling
343
+ /// It is the callers responsibility to check bounds and alignment beforehand.
346
344
pub fn read_scalar (
347
345
& self ,
348
346
cx : & impl HasDataLayout ,
@@ -378,7 +376,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
378
376
Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: from_uint ( bits, size) ) )
379
377
}
380
378
381
- /// Note: This function does not do *any* alignment checks, you need to do these before calling
379
+ /// Read a pointer-sized scalar.
380
+ ///
381
+ /// It is the callers responsibility to check bounds and alignment beforehand.
382
382
pub fn read_ptr_sized (
383
383
& self ,
384
384
cx : & impl HasDataLayout ,
@@ -395,7 +395,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
395
395
/// * in oder to obtain a `Pointer` we need to check for ZSTness anyway due to integer pointers
396
396
/// being valid for ZSTs
397
397
///
398
- /// Note: This function does not do *any* alignment checks, you need to do these before calling
398
+ /// It is the callers responsibility to check bounds and alignment beforehand.
399
399
pub fn write_scalar (
400
400
& mut self ,
401
401
cx : & impl HasDataLayout ,
@@ -435,7 +435,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
435
435
Ok ( ( ) )
436
436
}
437
437
438
- /// Note: This function does not do *any* alignment checks, you need to do these before calling
438
+ /// Write a pointer-sized scalar.
439
+ ///
440
+ /// It is the callers responsibility to check bounds and alignment beforehand.
439
441
pub fn write_ptr_sized (
440
442
& mut self ,
441
443
cx : & impl HasDataLayout ,
0 commit comments