Skip to content

Commit f6fef3b

Browse files
authored
Merge pull request #691 from RalfJung/pragmatic-ptr-eq
be pragmatic about ptr-int comparisons, for now
2 parents 7c06679 + af2b42d commit f6fef3b

File tree

3 files changed

+19
-7
lines changed

3 files changed

+19
-7
lines changed

src/operator.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
152152
// This accepts one-past-the end. Thus, there is still technically
153153
// some non-determinism that we do not fully rule out when two
154154
// allocations sit right next to each other. The C/C++ standards are
155-
// somewhat fuzzy about this case, so I think for now this check is
156-
// "good enough".
155+
// somewhat fuzzy about this case, so pragmatically speaking I think
156+
// for now this check is "good enough".
157+
// FIXME: Once we support intptrcast, we could try to fix these holes.
157158
// Dead allocations in miri cannot overlap with live allocations, but
158159
// on read hardware this can easily happen. Thus for comparisons we require
159160
// both pointers to be live.
@@ -169,8 +170,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
169170
assert_eq!(size as u64, self.pointer_size().bytes());
170171
let bits = bits as u64;
171172

172-
// Case I: Comparing with NULL.
173-
if bits == 0 {
173+
// Case I: Comparing real pointers with "small" integers.
174+
// Really we should only do this for NULL, but pragmatically speaking on non-bare-metal systems,
175+
// an allocation will never be at the very bottom of the address space.
176+
// Such comparisons can arise when comparing empty slices, which sometimes are "fake"
177+
// integer pointers (okay because the slice is empty) and sometimes point into a
178+
// real allocation.
179+
// The most common source of such integer pointers is `NonNull::dangling()`, which
180+
// equals the type's alignment. i128 might have an alignment of 16 bytes, but few types have
181+
// alignment 32 or higher, hence the limit of 32.
182+
// FIXME: Once we support intptrcast, we could try to fix these holes.
183+
if bits < 32 {
174184
// Test if the ptr is in-bounds. Then it cannot be NULL.
175185
// Even dangling pointers cannot be NULL.
176186
if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok() {

tests/compile-fail/ptr_eq_integer.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
use std::mem;
2-
31
fn main() {
42
let b = Box::new(0);
53
let x = &*b as *const i32;
64
// We cannot compare this with a non-NULL integer. After all, these *could* be equal (with the right base address).
7-
assert!(x != mem::align_of::<i32>() as *const i32); //~ ERROR invalid arithmetic on pointers
5+
assert!(x != 64 as *const i32); //~ ERROR invalid arithmetic on pointers
86
}

tests/run-pass/vecs.rs

+4
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,8 @@ fn main() {
8585
assert_eq!(make_vec_macro(), [1, 2]);
8686
assert_eq!(make_vec_macro_repeat(), [42; 5]);
8787
assert_eq!(make_vec_macro_repeat_zeroed(), [0; 7]);
88+
89+
// Test interesting empty slice comparison
90+
// (one is a real pointer, one an integer pointer).
91+
assert_eq!((200..-5).step_by(1).collect::<Vec<isize>>(), []);
8892
}

0 commit comments

Comments
 (0)