@@ -56,8 +56,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
5656
5757 trace ! ( "ptr_op: {:?} {:?} {:?}" , * left, bin_op, * right) ;
5858
59- // If intptrcast is enabled, treat everything of integer *type* at integer *value*.
60- if self . memory ( ) . extra . rng . is_some ( ) && left. layout . ty . is_integral ( ) {
59+ // Treat everything of integer *type* at integer *value*.
60+ if left. layout . ty . is_integral ( ) {
6161 // This is actually an integer operation, so dispatch back to the core engine.
6262 // TODO: Once intptrcast is the default, librustc_mir should never even call us
6363 // for integer types.
@@ -188,104 +188,11 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
188188 right : Scalar < Tag > ,
189189 ) -> InterpResult < ' tcx , bool > {
190190 let size = self . pointer_size ( ) ;
191- if self . memory ( ) . extra . rng . is_some ( ) {
192- // Just compare the integers.
193- // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers?
194- let left = self . force_bits ( left, size) ?;
195- let right = self . force_bits ( right, size) ?;
196- return Ok ( left == right) ;
197- }
198- Ok ( match ( left, right) {
199- ( Scalar :: Raw { .. } , Scalar :: Raw { .. } ) =>
200- left. to_bits ( size) ? == right. to_bits ( size) ?,
201- ( Scalar :: Ptr ( left) , Scalar :: Ptr ( right) ) => {
202- // Comparison illegal if one of them is out-of-bounds, *unless* they
203- // are in the same allocation.
204- if left. alloc_id == right. alloc_id {
205- left. offset == right. offset
206- } else {
207- // Make sure both pointers are in-bounds.
208- // This accepts one-past-the end. Thus, there is still technically
209- // some non-determinism that we do not fully rule out when two
210- // allocations sit right next to each other. The C/C++ standards are
211- // somewhat fuzzy about this case, so pragmatically speaking I think
212- // for now this check is "good enough".
213- // FIXME: Once we support intptrcast, we could try to fix these holes.
214- // Dead allocations in miri cannot overlap with live allocations, but
215- // on read hardware this can easily happen. Thus for comparisons we require
216- // both pointers to be live.
217- if self . pointer_inbounds ( left) . is_ok ( ) && self . pointer_inbounds ( right) . is_ok ( ) {
218- // Two in-bounds (and hence live) pointers in different allocations are different.
219- false
220- } else {
221- return err ! ( InvalidPointerMath ) ;
222- }
223- }
224- }
225- // Comparing ptr and integer.
226- ( Scalar :: Ptr ( ptr) , Scalar :: Raw { data, size } ) |
227- ( Scalar :: Raw { data, size } , Scalar :: Ptr ( ptr) ) => {
228- assert_eq ! ( size as u64 , self . pointer_size( ) . bytes( ) ) ;
229- let bits = data as u64 ;
230-
231- // Case I: Comparing real pointers with "small" integers.
232- // Really we should only do this for NULL, but pragmatically speaking on non-bare-metal systems,
233- // an allocation will never be at the very bottom of the address space.
234- // Such comparisons can arise when comparing empty slices, which sometimes are "fake"
235- // integer pointers (okay because the slice is empty) and sometimes point into a
236- // real allocation.
237- // The most common source of such integer pointers is `NonNull::dangling()`, which
238- // equals the type's alignment. i128 might have an alignment of 16 bytes, but few types have
239- // alignment 32 or higher, hence the limit of 32.
240- // FIXME: Once we support intptrcast, we could try to fix these holes.
241- if bits < 32 {
242- // Test if the pointer can be different from NULL or not.
243- // We assume that pointers that are not NULL are also not "small".
244- if !self . memory ( ) . ptr_may_be_null ( ptr) {
245- return Ok ( false ) ;
246- }
247- }
248-
249- let ( alloc_size, alloc_align) = self . memory ( )
250- . get_size_and_align ( ptr. alloc_id , AllocCheck :: MaybeDead )
251- . expect ( "alloc info with MaybeDead cannot fail" ) ;
252-
253- // Case II: Alignment gives it away
254- if ptr. offset . bytes ( ) % alloc_align. bytes ( ) == 0 {
255- // The offset maintains the allocation alignment, so we know `base+offset`
256- // is aligned by `alloc_align`.
257- // FIXME: We could be even more general, e.g., offset 2 into a 4-aligned
258- // allocation cannot equal 3.
259- if bits % alloc_align. bytes ( ) != 0 {
260- // The integer is *not* aligned. So they cannot be equal.
261- return Ok ( false ) ;
262- }
263- }
264- // Case III: The integer is too big, and the allocation goes on a bit
265- // without wrapping around the address space.
266- {
267- // Compute the highest address at which this allocation could live.
268- // Substract one more, because it must be possible to add the size
269- // to the base address without overflowing; that is, the very last address
270- // of the address space is never dereferencable (but it can be in-bounds, i.e.,
271- // one-past-the-end).
272- let max_base_addr =
273- ( ( 1u128 << self . pointer_size ( ) . bits ( ) )
274- - u128:: from ( alloc_size. bytes ( ) )
275- - 1
276- ) as u64 ;
277- if let Some ( max_addr) = max_base_addr. checked_add ( ptr. offset . bytes ( ) ) {
278- if bits > max_addr {
279- // The integer is too big, this cannot possibly be equal.
280- return Ok ( false )
281- }
282- }
283- }
284-
285- // None of the supported cases.
286- return err ! ( InvalidPointerMath ) ;
287- }
288- } )
191+ // Just compare the integers.
192+ // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers?
193+ let left = self . force_bits ( left, size) ?;
194+ let right = self . force_bits ( right, size) ?;
195+ Ok ( left == right)
289196 }
290197
291198 fn ptr_int_arithmetic (
0 commit comments