Skip to content

Commit

Permalink
Rollup merge of #130107 - RalfJung:const-ptr-is-null, r=oli-obk
Browse files Browse the repository at this point in the history
const: make ptr.is_null() stop execution on ambiguity

This seems better than saying `false` -- saying `false` is in fact actively unsound if `NonNull` then uses this to permit putting this pointer inside of it, but at runtime it turns out to be null.

Part of #74939
Cc ``@rust-lang/wg-const-eval``
  • Loading branch information
workingjubilee committed Sep 9, 2024
2 parents 9b15f6e + 11d51aa commit d77ff79
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 20 deletions.
10 changes: 6 additions & 4 deletions library/core/src/ptr/const_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,17 @@ impl<T: ?Sized> *const T {

#[inline]
const fn const_impl(ptr: *const u8) -> bool {
// Compare via a cast to a thin pointer, so fat pointers are only
// considering their "data" part for null-ness.
match (ptr).guaranteed_eq(null_mut()) {
None => false,
Some(res) => res,
// To remain maximally convervative, we stop execution when we don't
// know whether the pointer is null or not.
// We can *not* return `false` here, that would be unsound in `NonNull::new`!
None => panic!("null-ness of this pointer cannot be determined in const context"),
}
}

#[allow(unused_unsafe)]
// Compare via a cast to a thin pointer, so fat pointers are only
// considering their "data" part for null-ness.
const_eval_select((self as *const u8,), const_impl, runtime_impl)
}

Expand Down
17 changes: 1 addition & 16 deletions library/core/src/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,7 @@ impl<T: ?Sized> *mut T {
#[rustc_diagnostic_item = "ptr_is_null"]
#[inline]
pub const fn is_null(self) -> bool {
#[inline]
fn runtime_impl(ptr: *mut u8) -> bool {
ptr.addr() == 0
}

#[inline]
const fn const_impl(ptr: *mut u8) -> bool {
// Compare via a cast to a thin pointer, so fat pointers are only
// considering their "data" part for null-ness.
match (ptr).guaranteed_eq(null_mut()) {
None => false,
Some(res) => res,
}
}

const_eval_select((self as *mut u8,), const_impl, runtime_impl)
self.cast_const().is_null()
}

/// Casts to a pointer of another type.
Expand Down
20 changes: 20 additions & 0 deletions tests/ui/consts/const-ptr-is-null.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#![feature(const_ptr_is_null)]
use std::ptr;

const IS_NULL: () = {
assert!(ptr::null::<u8>().is_null());
};
const IS_NOT_NULL: () = {
assert!(!ptr::null::<u8>().wrapping_add(1).is_null());
};

const MAYBE_NULL: () = {
let x = 15;
let ptr = &x as *const i32;
// This one is still unambiguous...
assert!(!ptr.is_null());
// but once we shift outside the allocation, we might become null.
assert!(!ptr.wrapping_sub(512).is_null()); //~inside `MAYBE_NULL`
};

fn main() {}
19 changes: 19 additions & 0 deletions tests/ui/consts/const-ptr-is-null.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
= note: the evaluated program panicked at 'null-ness of this pointer cannot be determined in const context', $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
note: inside `std::ptr::const_ptr::<impl *const T>::is_null::const_impl`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
note: inside `std::ptr::const_ptr::<impl *const i32>::is_null`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
note: inside `MAYBE_NULL`
--> $DIR/const-ptr-is-null.rs:17:14
|
LL | assert!(!ptr.wrapping_sub(512).is_null());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0080`.

0 comments on commit d77ff79

Please sign in to comment.