Merge pull request #691 from RalfJung/pragmatic-ptr-eq

be pragmatic about ptr-int comparisons, for now
This commit is contained in:
Oliver Scherer 2019-04-16 20:52:55 +02:00 committed by GitHub
commit f6fef3b08b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 7 deletions

View File

@ -152,8 +152,9 @@ fn ptr_eq(
// This accepts one-past-the end. Thus, there is still technically // This accepts one-past-the end. Thus, there is still technically
// some non-determinism that we do not fully rule out when two // some non-determinism that we do not fully rule out when two
// allocations sit right next to each other. The C/C++ standards are // 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 // somewhat fuzzy about this case, so pragmatically speaking I think
// "good enough". // 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 // Dead allocations in miri cannot overlap with live allocations, but
// on read hardware this can easily happen. Thus for comparisons we require // on read hardware this can easily happen. Thus for comparisons we require
// both pointers to be live. // both pointers to be live.
@ -169,8 +170,17 @@ fn ptr_eq(
assert_eq!(size as u64, self.pointer_size().bytes()); assert_eq!(size as u64, self.pointer_size().bytes());
let bits = bits as u64; let bits = bits as u64;
// Case I: Comparing with NULL. // Case I: Comparing real pointers with "small" integers.
if bits == 0 { // 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. // Test if the ptr is in-bounds. Then it cannot be NULL.
// Even dangling pointers cannot be NULL. // Even dangling pointers cannot be NULL.
if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok() { if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok() {

View File

@ -1,8 +1,6 @@
use std::mem;
fn main() { fn main() {
let b = Box::new(0); let b = Box::new(0);
let x = &*b as *const i32; 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). // 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::<i32>() as *const i32); //~ ERROR invalid arithmetic on pointers assert!(x != 64 as *const i32); //~ ERROR invalid arithmetic on pointers
} }

View File

@ -85,4 +85,8 @@ fn main() {
assert_eq!(make_vec_macro(), [1, 2]); assert_eq!(make_vec_macro(), [1, 2]);
assert_eq!(make_vec_macro_repeat(), [42; 5]); assert_eq!(make_vec_macro_repeat(), [42; 5]);
assert_eq!(make_vec_macro_repeat_zeroed(), [0; 7]); 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::<Vec<isize>>(), []);
} }