about summary refs log tree commit diff
diff options
context:
space:
mode:
author许杰友 Jieyou Xu (Joe) <39484203+jieyouxu@users.noreply.github.com>2025-02-03 19:13:27 +0800
committerGitHub <noreply@github.com>2025-02-03 19:13:27 +0800
commit43764db758fd404083f22d0bde747b5ce5ca1cfa (patch)
tree5c8dbdf85a92588398853b8e0f664231fbee81ff
parent1df7b30926b10f3458d4c87078c6c0ef87ad86c8 (diff)
parent788a38953f11cef41663cb912d51126cb595fef4 (diff)
downloadrust-43764db758fd404083f22d0bde747b5ce5ca1cfa.tar.gz
rust-43764db758fd404083f22d0bde747b5ce5ca1cfa.zip
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
-rw-r--r--compiler/rustc_const_eval/messages.ftl4
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs20
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.stderr15
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs7
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr15
-rw-r--r--tests/ui/const-ptr/forbidden_slices.stderr4
-rw-r--r--tests/ui/consts/offset_from_ub.rs10
-rw-r--r--tests/ui/consts/offset_from_ub.stderr14
11 files changed, 81 insertions, 19 deletions
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index d600d223bff..eecc6690f51 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -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 =
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 9f5f2533e08..4ca317e3a1e 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -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(
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.rs
new file mode 100644
index 00000000000..5a997ad8ec4
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.rs
@@ -0,0 +1,5 @@
+fn main() {
+    unsafe {
+        (&1_u8 as *const u8).offset_from(&2_u8); //~ERROR: not both derived from the same allocation
+    }
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.stderr
new file mode 100644
index 00000000000..34d7c6a8021
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.stderr
@@ -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
+
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs
index 0acda559d3a..0d34e711ca7 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs
@@ -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
     }
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr
index 7ef66390fcd..897945d6d5d 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr
@@ -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
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs
new file mode 100644
index 00000000000..06f6b7a0117
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs
@@ -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
+    }
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr
new file mode 100644
index 00000000000..67df633bef5
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr
@@ -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
+
diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr
index fad078ad2b2..2e0c04dcf1e 100644
--- a/tests/ui/const-ptr/forbidden_slices.stderr
+++ b/tests/ui/const-ptr/forbidden_slices.stderr
@@ -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
diff --git a/tests/ui/consts/offset_from_ub.rs b/tests/ui/consts/offset_from_ub.rs
index 0232b03a813..88356900605 100644
--- a/tests/ui/consts/offset_from_ub.rs
+++ b/tests/ui/consts/offset_from_ub.rs
@@ -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 = {
diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr
index ac4597ff011..1379365cc25 100644
--- a/tests/ui/consts/offset_from_ub.stderr
+++ b/tests/ui/consts/offset_from_ub.stderr
@@ -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