@@ -6,44 +6,13 @@ use super::{
66
77use crate :: ty:: layout:: { Size , Align } ;
88use syntax:: ast:: Mutability ;
9- use std:: { iter, fmt :: { self , Display } } ;
9+ use std:: iter;
1010use crate :: mir;
11- use std:: ops:: { Deref , DerefMut } ;
11+ use std:: ops:: { Range , Deref , DerefMut } ;
1212use rustc_data_structures:: sorted_map:: SortedMap ;
13- use rustc_macros:: HashStable ;
1413use rustc_target:: abi:: HasDataLayout ;
1514use std:: borrow:: Cow ;
1615
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-
4716#[ derive( Clone , Debug , Eq , PartialEq , PartialOrd , Ord , Hash , RustcEncodable , RustcDecodable ) ]
4817pub struct Allocation < Tag =( ) , Extra =( ) > {
4918 /// The actual bytes of the allocation.
@@ -146,54 +115,48 @@ impl<Tag> Allocation<Tag> {
146115
147116impl < ' tcx > :: serialize:: UseSpecializedDecodable for & ' tcx Allocation { }
148117
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 (
167124 & 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
175140 }
176- }
177141
178- /// Byte accessors
179- impl < ' tcx , Tag : Copy , Extra : AllocationExtra < Tag > > Allocation < Tag , Extra > {
180142 /// The last argument controls whether we error out when there are undefined
181143 /// or pointer bytes. You should never call this, call `get_bytes` or
182144 /// `get_bytes_with_undef_and_ptr` instead,
183145 ///
184146 /// This function also guarantees that the resulting pointer will remain stable
185147 /// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies
186148 /// on that.
149+ ///
150+ /// It is the caller's responsibility to check bounds and alignment beforehand.
187151 fn get_bytes_internal (
188152 & self ,
189153 cx : & impl HasDataLayout ,
190154 ptr : Pointer < Tag > ,
191155 size : Size ,
192156 check_defined_and_ptr : bool ,
193- msg : CheckInAllocMsg ,
194157 ) -> InterpResult < ' tcx , & [ u8 ] >
195158 {
196- self . check_bounds ( cx , ptr, size, msg ) ? ;
159+ let range = self . check_bounds ( ptr. offset , size) ;
197160
198161 if check_defined_and_ptr {
199162 self . check_defined ( ptr, size) ?;
@@ -205,12 +168,13 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
205168
206169 AllocationExtra :: memory_read ( self , ptr, size) ?;
207170
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] )
212172 }
213173
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.
214178 #[ inline]
215179 pub fn get_bytes (
216180 & self ,
@@ -219,11 +183,13 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
219183 size : Size ,
220184 ) -> InterpResult < ' tcx , & [ u8 ] >
221185 {
222- self . get_bytes_internal ( cx, ptr, size, true , CheckInAllocMsg :: MemoryAccessTest )
186+ self . get_bytes_internal ( cx, ptr, size, true )
223187 }
224188
225189 /// It is the caller's responsibility to handle undefined and pointer bytes.
226190 /// 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.
227193 #[ inline]
228194 pub fn get_bytes_with_undef_and_ptr (
229195 & self ,
@@ -232,30 +198,28 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
232198 size : Size ,
233199 ) -> InterpResult < ' tcx , & [ u8 ] >
234200 {
235- self . get_bytes_internal ( cx, ptr, size, false , CheckInAllocMsg :: MemoryAccessTest )
201+ self . get_bytes_internal ( cx, ptr, size, false )
236202 }
237203
238204 /// Just calling this already marks everything as defined and removes relocations,
239205 /// so be sure to actually put data there!
206+ ///
207+ /// It is the caller's responsibility to check bounds and alignment beforehand.
240208 pub fn get_bytes_mut (
241209 & mut self ,
242210 cx : & impl HasDataLayout ,
243211 ptr : Pointer < Tag > ,
244212 size : Size ,
245213 ) -> InterpResult < ' tcx , & mut [ u8 ] >
246214 {
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) ;
249216
250217 self . mark_definedness ( ptr, size, true ) ;
251218 self . clear_relocations ( cx, ptr, size) ?;
252219
253220 AllocationExtra :: memory_written ( self , ptr, size) ?;
254221
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] )
259223 }
260224}
261225
@@ -276,9 +240,10 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
276240 let size_with_null = Size :: from_bytes ( ( size + 1 ) as u64 ) ;
277241 // Go through `get_bytes` for checks and AllocationExtra hooks.
278242 // 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.
280244 Ok ( & self . get_bytes ( cx, ptr, size_with_null) ?[ ..size] )
281245 }
246+ // This includes the case where `offset` is out-of-bounds to begin with.
282247 None => err ! ( UnterminatedCString ( ptr. erase_tag( ) ) ) ,
283248 }
284249 }
@@ -306,7 +271,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
306271
307272 /// Writes `src` to the memory starting at `ptr.offset`.
308273 ///
309- /// Will do bounds checks on the allocation .
274+ /// It is the caller's responsibility to check bounds and alignment beforehand .
310275 pub fn write_bytes (
311276 & mut self ,
312277 cx : & impl HasDataLayout ,
@@ -320,6 +285,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
320285 }
321286
322287 /// 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.
323290 pub fn write_repeat (
324291 & mut self ,
325292 cx : & impl HasDataLayout ,
@@ -342,7 +309,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
342309 /// * in oder to obtain a `Pointer` we need to check for ZSTness anyway due to integer pointers
343310 /// being valid for ZSTs
344311 ///
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.
346313 pub fn read_scalar (
347314 & self ,
348315 cx : & impl HasDataLayout ,
@@ -378,7 +345,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
378345 Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: from_uint ( bits, size) ) )
379346 }
380347
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.
382351 pub fn read_ptr_sized (
383352 & self ,
384353 cx : & impl HasDataLayout ,
@@ -395,7 +364,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
395364 /// * in oder to obtain a `Pointer` we need to check for ZSTness anyway due to integer pointers
396365 /// being valid for ZSTs
397366 ///
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.
399368 pub fn write_scalar (
400369 & mut self ,
401370 cx : & impl HasDataLayout ,
@@ -435,7 +404,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
435404 Ok ( ( ) )
436405 }
437406
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.
439410 pub fn write_ptr_sized (
440411 & mut self ,
441412 cx : & impl HasDataLayout ,
0 commit comments