Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 86c4e0e

Browse files
committedMay 9, 2024
interpret/miri: better errors on failing offset_from
1 parent 5bbe84f commit 86c4e0e

File tree

6 files changed

+67
-27
lines changed

6 files changed

+67
-27
lines changed
 

‎compiler/rustc_const_eval/messages.ftl

+8-7
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,6 @@ const_eval_deref_function_pointer =
6969
accessing {$allocation} which contains a function
7070
const_eval_deref_vtable_pointer =
7171
accessing {$allocation} which contains a vtable
72-
const_eval_different_allocations =
73-
`{$name}` called on pointers into different allocations
74-
7572
const_eval_division_by_zero =
7673
dividing by zero
7774
const_eval_division_overflow =
@@ -234,12 +231,18 @@ const_eval_not_enough_caller_args =
234231
const_eval_nullary_intrinsic_fail =
235232
could not evaluate nullary intrinsic
236233
234+
const_eval_offset_from_different_allocations =
235+
`{$name}` called on pointers into different allocations
236+
const_eval_offset_from_different_integers =
237+
`{$name}` called on different pointers without provenance (i.e., without an associated allocation)
237238
const_eval_offset_from_overflow =
238239
`{$name}` called when first pointer is too far ahead of second
239-
240-
const_eval_offset_from_test = out-of-bounds `offset_from`
240+
const_eval_offset_from_test =
241+
out-of-bounds `offset_from`
241242
const_eval_offset_from_underflow =
242243
`{$name}` called when first pointer is too far before second
244+
const_eval_offset_from_unsigned_overflow =
245+
`ptr_offset_from_unsigned` called when first pointer has smaller offset than second: {$a_offset} < {$b_offset}
243246
244247
const_eval_operator_non_const =
245248
cannot call non-const operator in {const_eval_const_context}s
@@ -381,8 +384,6 @@ const_eval_unreachable = entering unreachable code
381384
const_eval_unreachable_unwind =
382385
unwinding past a stack frame that does not allow unwinding
383386
384-
const_eval_unsigned_offset_from_overflow =
385-
`ptr_offset_from_unsigned` called when first pointer has smaller offset than second: {$a_offset} < {$b_offset}
386387
const_eval_unsized_local = unsized locals are not supported
387388
const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
388389

‎compiler/rustc_const_eval/src/interpret/intrinsics.rs

+16-13
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,16 @@ use rustc_middle::ty::layout::{LayoutOf as _, ValidityRequirement};
88
use rustc_middle::ty::GenericArgsRef;
99
use rustc_middle::ty::{Ty, TyCtxt};
1010
use rustc_middle::{
11-
mir::{
12-
self,
13-
interpret::{
14-
Allocation, ConstAllocation, GlobalId, InterpResult, PointerArithmetic, Scalar,
15-
},
16-
BinOp, ConstValue, NonDivergingIntrinsic,
17-
},
11+
mir::{self, BinOp, ConstValue, NonDivergingIntrinsic},
1812
ty::layout::TyAndLayout,
1913
};
2014
use rustc_span::symbol::{sym, Symbol};
2115
use rustc_target::abi::Size;
2216

2317
use super::{
24-
memory::MemoryKind, util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx,
25-
MPlaceTy, Machine, OpTy, Pointer,
18+
memory::MemoryKind, util::ensure_monomorphic_enough, Allocation, CheckInAllocMsg,
19+
ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Pointer,
20+
PointerArithmetic, Scalar,
2621
};
2722

2823
use crate::fluent_generated as fluent;
@@ -249,22 +244,30 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
249244
match (self.ptr_try_get_alloc_id(a), self.ptr_try_get_alloc_id(b)) {
250245
(Err(a), Err(b)) => {
251246
// Neither pointer points to an allocation.
252-
// If these are inequal, this *will* fail the deref check below.
247+
// This is okay only if they are the same.
248+
if a != b {
249+
// We'd catch this below in the "dereferenceable" check, but
250+
// show a nicer error for this particular case.
251+
throw_ub_custom!(
252+
fluent::const_eval_offset_from_different_integers,
253+
name = intrinsic_name,
254+
);
255+
}
253256
(a, b)
254257
}
255258
(Err(_), _) | (_, Err(_)) => {
256259
// We managed to find a valid allocation for one pointer, but not the other.
257260
// That means they are definitely not pointing to the same allocation.
258261
throw_ub_custom!(
259-
fluent::const_eval_different_allocations,
262+
fluent::const_eval_offset_from_different_allocations,
260263
name = intrinsic_name,
261264
);
262265
}
263266
(Ok((a_alloc_id, a_offset, _)), Ok((b_alloc_id, b_offset, _))) => {
264267
// Found allocation for both. They must be into the same allocation.
265268
if a_alloc_id != b_alloc_id {
266269
throw_ub_custom!(
267-
fluent::const_eval_different_allocations,
270+
fluent::const_eval_offset_from_different_allocations,
268271
name = intrinsic_name,
269272
);
270273
}
@@ -286,7 +289,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
286289
// a < b
287290
if intrinsic_name == sym::ptr_offset_from_unsigned {
288291
throw_ub_custom!(
289-
fluent::const_eval_unsigned_offset_from_overflow,
292+
fluent::const_eval_offset_from_unsigned_overflow,
290293
a_offset = a_offset,
291294
b_offset = b_offset,
292295
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#![feature(strict_provenance)]
2+
use core::ptr;
3+
4+
fn main() {
5+
unsafe {
6+
let base = ptr::without_provenance::<()>(10);
7+
let unit = &*base;
8+
let p1 = unit as *const ();
9+
10+
let base = ptr::without_provenance::<()>(11);
11+
let unit = &*base;
12+
let p2 = unit as *const ();
13+
14+
// Seems to work because they are same pointer
15+
// even though it's dangling.
16+
let _ = p1.byte_offset_from(p1);
17+
18+
// UB because different pointers.
19+
let _ = p1.byte_offset_from(p2); //~ERROR: different pointers without provenance
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation)
2+
--> $DIR/ptr_offset_from_different_ints.rs:LL:CC
3+
|
4+
LL | let _ = p1.byte_offset_from(p2);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on different pointers without provenance (i.e., without an associated 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 $DIR/ptr_offset_from_different_ints.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/consts/offset_from_ub.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub const DIFFERENT_INT: isize = { // offset_from with two different integers: l
4242
let ptr1 = 8 as *const u8;
4343
let ptr2 = 16 as *const u8;
4444
unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed
45-
//~| 0x8[noalloc] is a dangling pointer
45+
//~| different pointers without provenance
4646
};
4747

4848
const OUT_OF_BOUNDS_1: isize = {
@@ -81,13 +81,13 @@ pub const DIFFERENT_ALLOC_UNSIGNED: usize = {
8181
};
8282

8383
pub const TOO_FAR_APART1: isize = {
84-
let ptr1 = ptr::null::<u8>();
84+
let ptr1 = &0u8 as *const u8;
8585
let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
8686
unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed
8787
//~| too far ahead
8888
};
8989
pub const TOO_FAR_APART2: isize = {
90-
let ptr1 = ptr::null::<u8>();
90+
let ptr1 = &0u8 as *const u8;
9191
let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
9292
unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed
9393
//~| too far before
@@ -100,7 +100,7 @@ const WRONG_ORDER_UNSIGNED: usize = {
100100
//~| first pointer has smaller offset than second: 0 < 8
101101
};
102102
pub const TOO_FAR_APART_UNSIGNED: usize = {
103-
let ptr1 = ptr::null::<u8>();
103+
let ptr1 = &0u8 as *const u8;
104104
let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
105105
// This would fit into a `usize` but we still don't allow it.
106106
unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } //~ERROR evaluation of constant value failed

‎tests/ui/consts/offset_from_ub.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ error[E0080]: evaluation of constant value failed
2727
--> $DIR/offset_from_ub.rs:44:14
2828
|
2929
LL | unsafe { ptr_offset_from(ptr2, ptr1) }
30-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: 0x8[noalloc] is a dangling pointer (it has no provenance)
30+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation)
3131

3232
error[E0080]: evaluation of constant value failed
3333
--> $DIR/offset_from_ub.rs:53:14
@@ -74,7 +74,7 @@ LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) }
7474
error[E0080]: evaluation of constant value failed
7575
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
7676
|
77-
= note: out-of-bounds `offset_from`: null pointer is a dangling pointer (it has no provenance)
77+
= note: `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation)
7878
|
7979
note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
8080
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -87,7 +87,7 @@ LL | unsafe { ptr2.offset_from(ptr1) }
8787
error[E0080]: evaluation of constant value failed
8888
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
8989
|
90-
= note: out-of-bounds `offset_from`: null pointer is a dangling pointer (it has no provenance)
90+
= note: `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation)
9191
|
9292
note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
9393
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL

0 commit comments

Comments
 (0)
Failed to load comments.