1
Fork 0

Rollup merge of #136438 - RalfJung:offset_from_ub_errors, r=oli-obk

miri: improve error when offset_from preconditions are violated

Fixes https://github.com/rust-lang/miri/issues/4143
This commit is contained in:
许杰友 Jieyou Xu (Joe) 2025-02-03 19:13:27 +08:00 committed by GitHub
commit 43764db758
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 81 additions and 19 deletions

View file

@ -280,7 +280,9 @@ const_eval_nullary_intrinsic_fail =
could not evaluate nullary intrinsic
const_eval_offset_from_different_allocations =
`{$name}` called on pointers into different allocations
`{$name}` called on two different pointers that are not both derived from the same allocation
const_eval_offset_from_out_of_bounds =
`{$name}` called on two different pointers where the memory range between them is not in-bounds of an allocation
const_eval_offset_from_overflow =
`{$name}` called when first pointer is too far ahead of second
const_eval_offset_from_test =

View file

@ -319,7 +319,25 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// Check that the memory between them is dereferenceable at all, starting from the
// origin pointer: `dist` is `a - b`, so it is based on `b`.
self.check_ptr_access_signed(b, dist, CheckInAllocMsg::OffsetFromTest)?;
self.check_ptr_access_signed(b, dist, CheckInAllocMsg::OffsetFromTest)
.map_err_kind(|_| {
// This could mean they point to different allocations, or they point to the same allocation
// but not the entire range between the pointers is in-bounds.
if let Ok((a_alloc_id, ..)) = self.ptr_try_get_alloc_id(a, 0)
&& let Ok((b_alloc_id, ..)) = self.ptr_try_get_alloc_id(b, 0)
&& a_alloc_id == b_alloc_id
{
err_ub_custom!(
fluent::const_eval_offset_from_out_of_bounds,
name = intrinsic_name,
)
} else {
err_ub_custom!(
fluent::const_eval_offset_from_different_allocations,
name = intrinsic_name,
)
}
})?;
// Then check that this is also dereferenceable from `a`. This ensures that they are
// derived from the same allocation.
self.check_ptr_access_signed(

View file

@ -0,0 +1,5 @@
fn main() {
unsafe {
(&1_u8 as *const u8).offset_from(&2_u8); //~ERROR: not both derived from the same allocation
}
}

View file

@ -0,0 +1,15 @@
error: Undefined Behavior: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
--> tests/fail/intrinsics/ptr_offset_from_different_allocs.rs:LL:CC
|
LL | (&1_u8 as *const u8).offset_from(&2_u8);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `main` at tests/fail/intrinsics/ptr_offset_from_different_allocs.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error

View file

@ -15,6 +15,6 @@ fn main() {
let _ = p1.byte_offset_from(p1);
// UB because different pointers.
let _ = p1.byte_offset_from(p2); //~ERROR: no provenance
let _ = p1.byte_offset_from(p2); //~ERROR: not both derived from the same allocation
}
}

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: out-of-bounds `offset_from` origin: expected a pointer to the end of 1 byte of memory, but got 0xb[noalloc] which is a dangling pointer (it has no provenance)
error: Undefined Behavior: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
--> tests/fail/intrinsics/ptr_offset_from_different_ints.rs:LL:CC
|
LL | let _ = p1.byte_offset_from(p2);
| ^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from` origin: expected a pointer to the end of 1 byte of memory, but got 0xb[noalloc] which is a dangling pointer (it has no provenance)
| ^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -0,0 +1,7 @@
fn main() {
let mem = [0u8; 1];
let ptr = mem.as_ptr();
unsafe {
ptr.wrapping_add(4).offset_from(ptr); //~ERROR: the memory range between them is not in-bounds of an allocation
}
}

View file

@ -0,0 +1,15 @@
error: Undefined Behavior: `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation
--> tests/fail/intrinsics/ptr_offset_from_oob.rs:LL:CC
|
LL | ptr.wrapping_add(4).offset_from(ptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `main` at tests/fail/intrinsics/ptr_offset_from_oob.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error

View file

@ -190,7 +190,7 @@ LL | from_ptr_range(ptr..ptr.add(1))
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
= note: `ptr_offset_from_unsigned` called on pointers into different allocations
= note: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation
|
note: inside `std::ptr::const_ptr::<impl *const u32>::sub_ptr`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@ -205,7 +205,7 @@ LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).ad
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
= note: `ptr_offset_from_unsigned` called on pointers into different allocations
= note: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation
|
note: inside `std::ptr::const_ptr::<impl *const u32>::sub_ptr`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL

View file

@ -17,7 +17,7 @@ pub const DIFFERENT_ALLOC: usize = {
let uninit2 = std::mem::MaybeUninit::<Struct>::uninit();
let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct;
let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) }; //~ERROR evaluation of constant value failed
//~| pointers into different allocations
//~| not both derived from the same allocation
offset as usize
};
@ -37,7 +37,7 @@ pub const DIFFERENT_INT: isize = { // offset_from with two different integers: l
let ptr1 = 8 as *const u8;
let ptr2 = 16 as *const u8;
unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed
//~| dangling pointer
//~| not both derived from the same allocation
};
const OUT_OF_BOUNDS_1: isize = {
@ -46,7 +46,7 @@ const OUT_OF_BOUNDS_1: isize = {
let end_ptr = (start_ptr).wrapping_add(length);
// First ptr is out of bounds
unsafe { ptr_offset_from(end_ptr, start_ptr) } //~ERROR evaluation of constant value failed
//~| expected a pointer to 10 bytes of memory
//~| the memory range between them is not in-bounds of an allocation
};
const OUT_OF_BOUNDS_2: isize = {
@ -55,7 +55,7 @@ const OUT_OF_BOUNDS_2: isize = {
let end_ptr = (start_ptr).wrapping_add(length);
// Second ptr is out of bounds
unsafe { ptr_offset_from(start_ptr, end_ptr) } //~ERROR evaluation of constant value failed
//~| expected a pointer to the end of 10 bytes of memory
//~| the memory range between them is not in-bounds of an allocation
};
pub const DIFFERENT_ALLOC_UNSIGNED: usize = {
@ -64,7 +64,7 @@ pub const DIFFERENT_ALLOC_UNSIGNED: usize = {
let uninit2 = std::mem::MaybeUninit::<Struct>::uninit();
let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct;
unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } //~ERROR evaluation of constant value failed
//~| pointers into different allocations
//~| not both derived from the same allocation
};
pub const TOO_FAR_APART1: isize = {

View file

@ -2,12 +2,12 @@ error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:19:27
|
LL | let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on pointers into different allocations
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
= note: `ptr_offset_from` called on pointers into different allocations
= note: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
|
note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@ -27,25 +27,25 @@ error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:39:14
|
LL | unsafe { ptr_offset_from(ptr2, ptr1) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from` origin: expected a pointer to $BYTES bytes of memory, but got 0x8[noalloc] which is a dangling pointer (it has no provenance)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:48:14
|
LL | unsafe { ptr_offset_from(end_ptr, start_ptr) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from` origin: expected a pointer to $BYTES bytes of memory, but got ALLOC0 which is only $BYTES bytes from the end of the allocation
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:57:14
|
LL | unsafe { ptr_offset_from(start_ptr, end_ptr) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from` origin: expected a pointer to the end of $BYTES bytes of memory, but got ALLOC1+0xa which does not have enough space to the beginning of the allocation
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:66:14
|
LL | unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation
error[E0080]: evaluation of constant value failed
--> $DIR/offset_from_ub.rs:73:14
@ -80,7 +80,7 @@ LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) }
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
= note: out-of-bounds `offset_from` origin: expected a pointer to $BYTES bytes of memory, but got a null pointer
= note: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
|
note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL