Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 43764db

Browse files
authored
Rollup merge of rust-lang#136438 - RalfJung:offset_from_ub_errors, r=oli-obk
miri: improve error when offset_from preconditions are violated Fixes rust-lang/miri#4143
2 parents 1df7b30 + 788a389 commit 43764db

File tree

11 files changed

+81
-19
lines changed

11 files changed

+81
-19
lines changed

compiler/rustc_const_eval/messages.ftl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,9 @@ const_eval_nullary_intrinsic_fail =
280280
could not evaluate nullary intrinsic
281281
282282
const_eval_offset_from_different_allocations =
283-
`{$name}` called on pointers into different allocations
283+
`{$name}` called on two different pointers that are not both derived from the same allocation
284+
const_eval_offset_from_out_of_bounds =
285+
`{$name}` called on two different pointers where the memory range between them is not in-bounds of an allocation
284286
const_eval_offset_from_overflow =
285287
`{$name}` called when first pointer is too far ahead of second
286288
const_eval_offset_from_test =

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,25 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
319319

320320
// Check that the memory between them is dereferenceable at all, starting from the
321321
// origin pointer: `dist` is `a - b`, so it is based on `b`.
322-
self.check_ptr_access_signed(b, dist, CheckInAllocMsg::OffsetFromTest)?;
322+
self.check_ptr_access_signed(b, dist, CheckInAllocMsg::OffsetFromTest)
323+
.map_err_kind(|_| {
324+
// This could mean they point to different allocations, or they point to the same allocation
325+
// but not the entire range between the pointers is in-bounds.
326+
if let Ok((a_alloc_id, ..)) = self.ptr_try_get_alloc_id(a, 0)
327+
&& let Ok((b_alloc_id, ..)) = self.ptr_try_get_alloc_id(b, 0)
328+
&& a_alloc_id == b_alloc_id
329+
{
330+
err_ub_custom!(
331+
fluent::const_eval_offset_from_out_of_bounds,
332+
name = intrinsic_name,
333+
)
334+
} else {
335+
err_ub_custom!(
336+
fluent::const_eval_offset_from_different_allocations,
337+
name = intrinsic_name,
338+
)
339+
}
340+
})?;
323341
// Then check that this is also dereferenceable from `a`. This ensures that they are
324342
// derived from the same allocation.
325343
self.check_ptr_access_signed(
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fn main() {
2+
unsafe {
3+
(&1_u8 as *const u8).offset_from(&2_u8); //~ERROR: not both derived from the same allocation
4+
}
5+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
2+
--> tests/fail/intrinsics/ptr_offset_from_different_allocs.rs:LL:CC
3+
|
4+
LL | (&1_u8 as *const u8).offset_from(&2_u8);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= note: BACKTRACE:
10+
= note: inside `main` at tests/fail/intrinsics/ptr_offset_from_different_allocs.rs:LL:CC
11+
12+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
13+
14+
error: aborting due to 1 previous error
15+

src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ fn main() {
1515
let _ = p1.byte_offset_from(p1);
1616

1717
// UB because different pointers.
18-
let _ = p1.byte_offset_from(p2); //~ERROR: no provenance
18+
let _ = p1.byte_offset_from(p2); //~ERROR: not both derived from the same allocation
1919
}
2020
}

src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
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)
1+
error: Undefined Behavior: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
22
--> tests/fail/intrinsics/ptr_offset_from_different_ints.rs:LL:CC
33
|
44
LL | let _ = p1.byte_offset_from(p2);
5-
| ^^^^^^^^^^^^^^^^^^^^^^^ 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)
5+
| ^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
let mem = [0u8; 1];
3+
let ptr = mem.as_ptr();
4+
unsafe {
5+
ptr.wrapping_add(4).offset_from(ptr); //~ERROR: the memory range between them is not in-bounds of an allocation
6+
}
7+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation
2+
--> tests/fail/intrinsics/ptr_offset_from_oob.rs:LL:CC
3+
|
4+
LL | ptr.wrapping_add(4).offset_from(ptr);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= note: BACKTRACE:
10+
= note: inside `main` at tests/fail/intrinsics/ptr_offset_from_oob.rs:LL:CC
11+
12+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
13+
14+
error: aborting due to 1 previous error
15+

tests/ui/const-ptr/forbidden_slices.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ LL | from_ptr_range(ptr..ptr.add(1))
190190
error[E0080]: could not evaluate static initializer
191191
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
192192
|
193-
= note: `ptr_offset_from_unsigned` called on pointers into different allocations
193+
= note: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation
194194
|
195195
note: inside `std::ptr::const_ptr::<impl *const u32>::sub_ptr`
196196
--> $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
205205
error[E0080]: could not evaluate static initializer
206206
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
207207
|
208-
= note: `ptr_offset_from_unsigned` called on pointers into different allocations
208+
= note: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation
209209
|
210210
note: inside `std::ptr::const_ptr::<impl *const u32>::sub_ptr`
211211
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL

tests/ui/consts/offset_from_ub.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub const DIFFERENT_ALLOC: usize = {
1717
let uninit2 = std::mem::MaybeUninit::<Struct>::uninit();
1818
let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct;
1919
let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) }; //~ERROR evaluation of constant value failed
20-
//~| pointers into different allocations
20+
//~| not both derived from the same allocation
2121
offset as usize
2222
};
2323

@@ -37,7 +37,7 @@ pub const DIFFERENT_INT: isize = { // offset_from with two different integers: l
3737
let ptr1 = 8 as *const u8;
3838
let ptr2 = 16 as *const u8;
3939
unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed
40-
//~| dangling pointer
40+
//~| not both derived from the same allocation
4141
};
4242

4343
const OUT_OF_BOUNDS_1: isize = {
@@ -46,7 +46,7 @@ const OUT_OF_BOUNDS_1: isize = {
4646
let end_ptr = (start_ptr).wrapping_add(length);
4747
// First ptr is out of bounds
4848
unsafe { ptr_offset_from(end_ptr, start_ptr) } //~ERROR evaluation of constant value failed
49-
//~| expected a pointer to 10 bytes of memory
49+
//~| the memory range between them is not in-bounds of an allocation
5050
};
5151

5252
const OUT_OF_BOUNDS_2: isize = {
@@ -55,7 +55,7 @@ const OUT_OF_BOUNDS_2: isize = {
5555
let end_ptr = (start_ptr).wrapping_add(length);
5656
// Second ptr is out of bounds
5757
unsafe { ptr_offset_from(start_ptr, end_ptr) } //~ERROR evaluation of constant value failed
58-
//~| expected a pointer to the end of 10 bytes of memory
58+
//~| the memory range between them is not in-bounds of an allocation
5959
};
6060

6161
pub const DIFFERENT_ALLOC_UNSIGNED: usize = {
@@ -64,7 +64,7 @@ pub const DIFFERENT_ALLOC_UNSIGNED: usize = {
6464
let uninit2 = std::mem::MaybeUninit::<Struct>::uninit();
6565
let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct;
6666
unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } //~ERROR evaluation of constant value failed
67-
//~| pointers into different allocations
67+
//~| not both derived from the same allocation
6868
};
6969

7070
pub const TOO_FAR_APART1: isize = {

0 commit comments

Comments
 (0)