@@ -111,6 +111,78 @@ impl<Tag, Extra: Default> Allocation<Tag, Extra> {
111111
112112impl < ' tcx > :: serialize:: UseSpecializedDecodable for & ' tcx Allocation { }
113113
114+ /// Various correctness checks for `Pointer`s
115+ impl < ' tcx , Tag : Copy , Extra > Allocation < Tag , Extra > {
116+ /// Check that the pointer is aligned AND non-NULL. This supports ZSTs in two ways:
117+ /// You can pass a scalar, and a `Pointer` does not have to actually still be allocated.
118+ pub fn check_align (
119+ & self ,
120+ ptr : Pointer < Tag > ,
121+ required_align : Align
122+ ) -> EvalResult < ' tcx > {
123+ // Check non-NULL/Undef, extract offset
124+
125+ // check this is not NULL -- which we can ensure only if this is in-bounds
126+ let size = Size :: from_bytes ( self . bytes . len ( ) as u64 ) ;
127+ if ptr. offset > size {
128+ return err ! ( PointerOutOfBounds {
129+ ptr: ptr. erase_tag( ) ,
130+ access: true ,
131+ allocation_size: size,
132+ } ) ;
133+ } ;
134+ // Check alignment
135+ if self . align . abi ( ) < required_align. abi ( ) {
136+ return err ! ( AlignmentCheckFailed {
137+ has: self . align,
138+ required: required_align,
139+ } ) ;
140+ }
141+ let offset = ptr. offset . bytes ( ) ;
142+ if offset % required_align. abi ( ) == 0 {
143+ Ok ( ( ) )
144+ } else {
145+ let has = offset % required_align. abi ( ) ;
146+ err ! ( AlignmentCheckFailed {
147+ has: Align :: from_bytes( has, has) . unwrap( ) ,
148+ required: required_align,
149+ } )
150+ }
151+ }
152+
153+ /// Check if the pointer is "in-bounds". Notice that a pointer pointing at the end
154+ /// of an allocation (i.e., at the first *inaccessible* location) *is* considered
155+ /// in-bounds! This follows C's/LLVM's rules. The `access` boolean is just used
156+ /// for the error message.
157+ /// If you want to check bounds before doing a memory access, be sure to
158+ /// check the pointer one past the end of your access, then everything will
159+ /// work out exactly.
160+ pub fn check_bounds_ptr ( & self , ptr : Pointer < Tag > , access : bool ) -> EvalResult < ' tcx > {
161+ let allocation_size = self . bytes . len ( ) as u64 ;
162+ if ptr. offset . bytes ( ) > allocation_size {
163+ return err ! ( PointerOutOfBounds {
164+ ptr: ptr. erase_tag( ) ,
165+ access,
166+ allocation_size: Size :: from_bytes( allocation_size) ,
167+ } ) ;
168+ }
169+ Ok ( ( ) )
170+ }
171+
172+ /// Check if the memory range beginning at `ptr` and of size `Size` is "in-bounds".
173+ #[ inline( always) ]
174+ pub fn check_bounds (
175+ & self ,
176+ cx : impl HasDataLayout ,
177+ ptr : Pointer < Tag > ,
178+ size : Size ,
179+ access : bool
180+ ) -> EvalResult < ' tcx > {
181+ // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
182+ self . check_bounds_ptr ( ptr. offset ( size, cx) ?, access)
183+ }
184+ }
185+
114186/// Byte accessors
115187impl < ' tcx , Tag : Copy , Extra : AllocationExtra < Tag > > Allocation < Tag , Extra > {
116188 /// The last argument controls whether we error out when there are undefined
@@ -527,78 +599,6 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
527599 }
528600}
529601
530- impl < ' tcx , Tag : Copy , Extra > Allocation < Tag , Extra > {
531- /// Check that the pointer is aligned AND non-NULL. This supports ZSTs in two ways:
532- /// You can pass a scalar, and a `Pointer` does not have to actually still be allocated.
533- pub fn check_align (
534- & self ,
535- ptr : Pointer < Tag > ,
536- required_align : Align
537- ) -> EvalResult < ' tcx > {
538- // Check non-NULL/Undef, extract offset
539-
540- // check this is not NULL -- which we can ensure only if this is in-bounds
541- let size = Size :: from_bytes ( self . bytes . len ( ) as u64 ) ;
542- if ptr. offset > size {
543- return err ! ( PointerOutOfBounds {
544- ptr: ptr. erase_tag( ) ,
545- access: true ,
546- allocation_size: size,
547- } ) ;
548- } ;
549- // Check alignment
550- if self . align . abi ( ) < required_align. abi ( ) {
551- return err ! ( AlignmentCheckFailed {
552- has: self . align,
553- required: required_align,
554- } ) ;
555- }
556- let offset = ptr. offset . bytes ( ) ;
557- if offset % required_align. abi ( ) == 0 {
558- Ok ( ( ) )
559- } else {
560- let has = offset % required_align. abi ( ) ;
561- err ! ( AlignmentCheckFailed {
562- has: Align :: from_bytes( has, has) . unwrap( ) ,
563- required: required_align,
564- } )
565- }
566- }
567-
568- /// Check if the pointer is "in-bounds". Notice that a pointer pointing at the end
569- /// of an allocation (i.e., at the first *inaccessible* location) *is* considered
570- /// in-bounds! This follows C's/LLVM's rules. The `access` boolean is just used
571- /// for the error message.
572- /// If you want to check bounds before doing a memory access, be sure to
573- /// check the pointer one past the end of your access, then everything will
574- /// work out exactly.
575- pub fn check_bounds_ptr ( & self , ptr : Pointer < Tag > , access : bool ) -> EvalResult < ' tcx > {
576- let allocation_size = self . bytes . len ( ) as u64 ;
577- if ptr. offset . bytes ( ) > allocation_size {
578- return err ! ( PointerOutOfBounds {
579- ptr: ptr. erase_tag( ) ,
580- access,
581- allocation_size: Size :: from_bytes( allocation_size) ,
582- } ) ;
583- }
584- Ok ( ( ) )
585- }
586-
587- /// Check if the memory range beginning at `ptr` and of size `Size` is "in-bounds".
588- #[ inline( always) ]
589- pub fn check_bounds (
590- & self ,
591- cx : impl HasDataLayout ,
592- ptr : Pointer < Tag > ,
593- size : Size ,
594- access : bool
595- ) -> EvalResult < ' tcx > {
596- // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
597- self . check_bounds_ptr ( ptr. offset ( size, cx) ?, access)
598- }
599- }
600-
601-
602602#[ derive( Clone , PartialEq , Eq , PartialOrd , Ord , Hash , Debug , RustcEncodable , RustcDecodable ) ]
603603pub struct Relocations < Tag =( ) , Id =AllocId > ( SortedMap < Size , ( Tag , Id ) > ) ;
604604
0 commit comments