@@ -8,7 +8,7 @@ use crate::ty::layout::{Size, Align};
88use syntax:: ast:: Mutability ;
99use std:: { iter, fmt:: { self , Display } } ;
1010use crate :: mir;
11- use std:: ops:: { Deref , DerefMut } ;
11+ use std:: ops:: { Range , Deref , DerefMut } ;
1212use rustc_data_structures:: sorted_map:: SortedMap ;
1313use rustc_macros:: HashStable ;
1414use rustc_target:: abi:: HasDataLayout ;
@@ -146,54 +146,48 @@ impl<Tag> Allocation<Tag> {
146146
147147impl < ' tcx > :: serialize:: UseSpecializedDecodable for & ' tcx Allocation { }
148148
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 (
156155 & 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
162171 }
163172
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 > {
180173 /// The last argument controls whether we error out when there are undefined
181174 /// or pointer bytes. You should never call this, call `get_bytes` or
182175 /// `get_bytes_with_undef_and_ptr` instead,
183176 ///
184177 /// This function also guarantees that the resulting pointer will remain stable
185178 /// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies
186179 /// on that.
180+ ///
181+ /// It is the callers responsibility to check bounds and alignment beforehand.
187182 fn get_bytes_internal (
188183 & self ,
189184 cx : & impl HasDataLayout ,
190185 ptr : Pointer < Tag > ,
191186 size : Size ,
192187 check_defined_and_ptr : bool ,
193- msg : CheckInAllocMsg ,
194188 ) -> InterpResult < ' tcx , & [ u8 ] >
195189 {
196- self . check_bounds ( cx , ptr, size, msg ) ? ;
190+ let range = self . check_bounds ( ptr. offset , size) ;
197191
198192 if check_defined_and_ptr {
199193 self . check_defined ( ptr, size) ?;
@@ -205,12 +199,13 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
205199
206200 AllocationExtra :: memory_read ( self , ptr, size) ?;
207201
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] )
212203 }
213204
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.
214209 #[ inline]
215210 pub fn get_bytes (
216211 & self ,
@@ -219,11 +214,13 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
219214 size : Size ,
220215 ) -> InterpResult < ' tcx , & [ u8 ] >
221216 {
222- self . get_bytes_internal ( cx, ptr, size, true , CheckInAllocMsg :: MemoryAccessTest )
217+ self . get_bytes_internal ( cx, ptr, size, true )
223218 }
224219
225220 /// It is the caller's responsibility to handle undefined and pointer bytes.
226221 /// 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.
227224 #[ inline]
228225 pub fn get_bytes_with_undef_and_ptr (
229226 & self ,
@@ -232,30 +229,28 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
232229 size : Size ,
233230 ) -> InterpResult < ' tcx , & [ u8 ] >
234231 {
235- self . get_bytes_internal ( cx, ptr, size, false , CheckInAllocMsg :: MemoryAccessTest )
232+ self . get_bytes_internal ( cx, ptr, size, false )
236233 }
237234
238235 /// Just calling this already marks everything as defined and removes relocations,
239236 /// so be sure to actually put data there!
237+ ///
238+ /// It is the callers responsibility to check bounds and alignment beforehand.
240239 pub fn get_bytes_mut (
241240 & mut self ,
242241 cx : & impl HasDataLayout ,
243242 ptr : Pointer < Tag > ,
244243 size : Size ,
245244 ) -> InterpResult < ' tcx , & mut [ u8 ] >
246245 {
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) ;
249247
250248 self . mark_definedness ( ptr, size, true ) ;
251249 self . clear_relocations ( cx, ptr, size) ?;
252250
253251 AllocationExtra :: memory_written ( self , ptr, size) ?;
254252
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] )
259254 }
260255}
261256
@@ -276,9 +271,10 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
276271 let size_with_null = Size :: from_bytes ( ( size + 1 ) as u64 ) ;
277272 // Go through `get_bytes` for checks and AllocationExtra hooks.
278273 // 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.
280275 Ok ( & self . get_bytes ( cx, ptr, size_with_null) ?[ ..size] )
281276 }
277+ // This includes the case where `offset` is out-of-bounds to begin with.
282278 None => err ! ( UnterminatedCString ( ptr. erase_tag( ) ) ) ,
283279 }
284280 }
@@ -306,7 +302,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
306302
307303 /// Writes `src` to the memory starting at `ptr.offset`.
308304 ///
309- /// Will do bounds checks on the allocation .
305+ /// It is the callers responsibility to check bounds and alignment beforehand .
310306 pub fn write_bytes (
311307 & mut self ,
312308 cx : & impl HasDataLayout ,
@@ -320,6 +316,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
320316 }
321317
322318 /// Sets `count` bytes starting at `ptr.offset` with `val`. Basically `memset`.
319+ ///
320+ /// It is the callers responsibility to check bounds and alignment beforehand.
323321 pub fn write_repeat (
324322 & mut self ,
325323 cx : & impl HasDataLayout ,
@@ -342,7 +340,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
342340 /// * in oder to obtain a `Pointer` we need to check for ZSTness anyway due to integer pointers
343341 /// being valid for ZSTs
344342 ///
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.
346344 pub fn read_scalar (
347345 & self ,
348346 cx : & impl HasDataLayout ,
@@ -378,7 +376,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
378376 Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: from_uint ( bits, size) ) )
379377 }
380378
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.
382382 pub fn read_ptr_sized (
383383 & self ,
384384 cx : & impl HasDataLayout ,
@@ -395,7 +395,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
395395 /// * in oder to obtain a `Pointer` we need to check for ZSTness anyway due to integer pointers
396396 /// being valid for ZSTs
397397 ///
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.
399399 pub fn write_scalar (
400400 & mut self ,
401401 cx : & impl HasDataLayout ,
@@ -435,7 +435,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
435435 Ok ( ( ) )
436436 }
437437
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.
439441 pub fn write_ptr_sized (
440442 & mut self ,
441443 cx : & impl HasDataLayout ,
0 commit comments