From 378d9d41720fe2a8a2aec1b39551d11fac6d8ec6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 17:47:37 +0200 Subject: [PATCH 1/2] be pragmatic about ptr-int comparisons, for now --- src/operator.rs | 18 ++++++++++++++---- tests/run-pass/vecs.rs | 4 ++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index a30b11aeb27d..45c0e63542dc 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -152,8 +152,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // This accepts one-past-the end. Thus, there is still technically // some non-determinism that we do not fully rule out when two // allocations sit right next to each other. The C/C++ standards are - // somewhat fuzzy about this case, so I think for now this check is - // "good enough". + // somewhat fuzzy about this case, so pragmatically speaking I think + // for now this check is "good enough". + // FIXME: Once we support intptrcast, we could try to fix these holes. // Dead allocations in miri cannot overlap with live allocations, but // on read hardware this can easily happen. Thus for comparisons we require // both pointers to be live. @@ -169,8 +170,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' assert_eq!(size as u64, self.pointer_size().bytes()); let bits = bits as u64; - // Case I: Comparing with NULL. - if bits == 0 { + // Case I: Comparing real pointers with "small" integers. + // Really we should only do this for NULL, but pragmatically speaking on non-bare-metal systems, + // an allocation will never be at the very bottom of the address space. + // Such comparisons can arise when comparing empty slices, which sometimes are "fake" + // integer pointers (okay because the slice is empty) and sometimes point into a + // real allocation. + // The most common source of such integer pointers is `NonNull::dangling()`, which + // equals the type's alignment. i128 might have an alignment of 16 bytes, but few types have + // alignment 32 or higher, hence the limit of 32. + // FIXME: Once we support intptrcast, we could try to fix these holes. + if bits < 32 { // Test if the ptr is in-bounds. Then it cannot be NULL. // Even dangling pointers cannot be NULL. if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok() { diff --git a/tests/run-pass/vecs.rs b/tests/run-pass/vecs.rs index bb9e5068f91e..739def804975 100644 --- a/tests/run-pass/vecs.rs +++ b/tests/run-pass/vecs.rs @@ -85,4 +85,8 @@ fn main() { assert_eq!(make_vec_macro(), [1, 2]); assert_eq!(make_vec_macro_repeat(), [42; 5]); assert_eq!(make_vec_macro_repeat_zeroed(), [0; 7]); + + // Test interesting empty slice comparison + // (one is a real pointer, one an integer pointer). + assert_eq!((200..-5).step_by(1).collect::>(), []); } From af2b42de0a43c0bf656e290e73a431acd033e79d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 19:09:37 +0200 Subject: [PATCH 2/2] fix compile-fail test --- tests/compile-fail/ptr_eq_integer.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/compile-fail/ptr_eq_integer.rs b/tests/compile-fail/ptr_eq_integer.rs index 10d5fbd517a3..396abaf4493b 100644 --- a/tests/compile-fail/ptr_eq_integer.rs +++ b/tests/compile-fail/ptr_eq_integer.rs @@ -1,8 +1,6 @@ -use std::mem; - fn main() { let b = Box::new(0); let x = &*b as *const i32; // We cannot compare this with a non-NULL integer. After all, these *could* be equal (with the right base address). - assert!(x != mem::align_of::() as *const i32); //~ ERROR invalid arithmetic on pointers + assert!(x != 64 as *const i32); //~ ERROR invalid arithmetic on pointers }