Skip to content

Commit

Permalink
Unrolled build for rust-lang#133700
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#133700 - RalfJung:const-non-null, r=lcnr

const-eval: detect more pointers as definitely not-null

This fixes rust-lang#133523 by making the `scalar_may_be_null` check smarter: for instance, an odd offset in any 2-aligned allocation can never be null, even if it is out-of-bounds.

More generally, if an allocation with unknown base address B is aligned to alignment N, and a pointer is at offset X inside that allocation, then we know that `(B + X) mod N = B mod N + X mod N = X mod N`. Since `0 mod N` is definitely 0, if we learn that `X mod N` is *not* 0 we can deduce that `B + X` is not 0.

This is immediately visible on stable, via `ptr.is_null()` (and, more subtly, by not raising a UB error when such a pointer is used somewhere that a non-null pointer is required). Therefore nominating for `@rust-lang/lang.`
  • Loading branch information
rust-timer authored Jan 18, 2025
2 parents efc2576 + e1dda10 commit 8974c02
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 10 deletions.
25 changes: 17 additions & 8 deletions compiler/rustc_const_eval/src/interpret/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1481,22 +1481,31 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Test if this value might be null.
/// If the machine does not support ptr-to-int casts, this is conservative.
pub fn scalar_may_be_null(&self, scalar: Scalar<M::Provenance>) -> InterpResult<'tcx, bool> {
interp_ok(match scalar.try_to_scalar_int() {
Ok(int) => int.is_null(),
match scalar.try_to_scalar_int() {
Ok(int) => interp_ok(int.is_null()),
Err(_) => {
// Can only happen during CTFE.
// We can't cast this pointer to an integer. Can only happen during CTFE.
let ptr = scalar.to_pointer(self)?;
match self.ptr_try_get_alloc_id(ptr, 0) {
Ok((alloc_id, offset, _)) => {
let size = self.get_alloc_info(alloc_id).size;
// If the pointer is out-of-bounds, it may be null.
// Note that one-past-the-end (offset == size) is still inbounds, and never null.
offset > size
let info = self.get_alloc_info(alloc_id);
// If the pointer is in-bounds (including "at the end"), it is definitely not null.
if offset <= info.size {
return interp_ok(false);
}
// If the allocation is N-aligned, and the offset is not divisible by N,
// then `base + offset` has a non-zero remainder after division by `N`,
// which means `base + offset` cannot be null.
if offset.bytes() % info.align.bytes() != 0 {
return interp_ok(false);
}
// We don't know enough, this might be null.
interp_ok(true)
}
Err(_offset) => bug!("a non-int scalar is always a pointer"),
}
}
})
}
}

/// Turning a "maybe pointer" into a proper pointer (and some information
Expand Down
8 changes: 7 additions & 1 deletion tests/ui/consts/const-ptr-is-null.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ const MAYBE_NULL: () = {
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.
// and in fact, any offset not visible by 4 (the alignment) cannot be null,
// even if it goes out-of-bounds...
assert!(!ptr.wrapping_byte_add(13).is_null());
assert!(!ptr.wrapping_byte_add(18).is_null());
assert!(!ptr.wrapping_byte_sub(1).is_null());
// ... but once we shift outside the allocation, with an offset divisible by 4,
// we might become null.
assert!(!ptr.wrapping_sub(512).is_null()); //~inside `MAYBE_NULL`
};

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/consts/const-ptr-is-null.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ note: inside `std::ptr::const_ptr::<impl *const T>::is_null::compiletime`
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:16:14
--> $DIR/const-ptr-is-null.rs:22:14
|
LL | assert!(!ptr.wrapping_sub(512).is_null());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down

0 comments on commit 8974c02

Please sign in to comment.