interpret/miri: better errors on failing offset_from
This commit is contained in:
parent
37dc766378
commit
41d36a0951
6 changed files with 67 additions and 27 deletions
|
@ -69,9 +69,6 @@ const_eval_deref_function_pointer =
|
|||
accessing {$allocation} which contains a function
|
||||
const_eval_deref_vtable_pointer =
|
||||
accessing {$allocation} which contains a vtable
|
||||
const_eval_different_allocations =
|
||||
`{$name}` called on pointers into different allocations
|
||||
|
||||
const_eval_division_by_zero =
|
||||
dividing by zero
|
||||
const_eval_division_overflow =
|
||||
|
@ -234,12 +231,18 @@ const_eval_not_enough_caller_args =
|
|||
const_eval_nullary_intrinsic_fail =
|
||||
could not evaluate nullary intrinsic
|
||||
|
||||
const_eval_offset_from_different_allocations =
|
||||
`{$name}` called on pointers into different allocations
|
||||
const_eval_offset_from_different_integers =
|
||||
`{$name}` called on different pointers without provenance (i.e., without an associated allocation)
|
||||
const_eval_offset_from_overflow =
|
||||
`{$name}` called when first pointer is too far ahead of second
|
||||
|
||||
const_eval_offset_from_test = out-of-bounds `offset_from`
|
||||
const_eval_offset_from_test =
|
||||
out-of-bounds `offset_from`
|
||||
const_eval_offset_from_underflow =
|
||||
`{$name}` called when first pointer is too far before second
|
||||
const_eval_offset_from_unsigned_overflow =
|
||||
`ptr_offset_from_unsigned` called when first pointer has smaller offset than second: {$a_offset} < {$b_offset}
|
||||
|
||||
const_eval_operator_non_const =
|
||||
cannot call non-const operator in {const_eval_const_context}s
|
||||
|
@ -381,8 +384,6 @@ const_eval_unreachable = entering unreachable code
|
|||
const_eval_unreachable_unwind =
|
||||
unwinding past a stack frame that does not allow unwinding
|
||||
|
||||
const_eval_unsigned_offset_from_overflow =
|
||||
`ptr_offset_from_unsigned` called when first pointer has smaller offset than second: {$a_offset} < {$b_offset}
|
||||
const_eval_unsized_local = unsized locals are not supported
|
||||
const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
|
||||
|
||||
|
|
|
@ -8,21 +8,16 @@ use rustc_middle::ty::layout::{LayoutOf as _, ValidityRequirement};
|
|||
use rustc_middle::ty::GenericArgsRef;
|
||||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use rustc_middle::{
|
||||
mir::{
|
||||
self,
|
||||
interpret::{
|
||||
Allocation, ConstAllocation, GlobalId, InterpResult, PointerArithmetic, Scalar,
|
||||
},
|
||||
BinOp, ConstValue, NonDivergingIntrinsic,
|
||||
},
|
||||
mir::{self, BinOp, ConstValue, NonDivergingIntrinsic},
|
||||
ty::layout::TyAndLayout,
|
||||
};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_target::abi::Size;
|
||||
|
||||
use super::{
|
||||
memory::MemoryKind, util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx,
|
||||
MPlaceTy, Machine, OpTy, Pointer,
|
||||
memory::MemoryKind, util::ensure_monomorphic_enough, Allocation, CheckInAllocMsg,
|
||||
ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Pointer,
|
||||
PointerArithmetic, Scalar,
|
||||
};
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
@ -249,14 +244,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
match (self.ptr_try_get_alloc_id(a), self.ptr_try_get_alloc_id(b)) {
|
||||
(Err(a), Err(b)) => {
|
||||
// Neither pointer points to an allocation.
|
||||
// If these are inequal or null, this *will* fail the deref check below.
|
||||
// This is okay only if they are the same.
|
||||
if a != b {
|
||||
// We'd catch this below in the "dereferenceable" check, but
|
||||
// show a nicer error for this particular case.
|
||||
throw_ub_custom!(
|
||||
fluent::const_eval_offset_from_different_integers,
|
||||
name = intrinsic_name,
|
||||
);
|
||||
}
|
||||
(a, b)
|
||||
}
|
||||
(Err(_), _) | (_, Err(_)) => {
|
||||
// We managed to find a valid allocation for one pointer, but not the other.
|
||||
// That means they are definitely not pointing to the same allocation.
|
||||
throw_ub_custom!(
|
||||
fluent::const_eval_different_allocations,
|
||||
fluent::const_eval_offset_from_different_allocations,
|
||||
name = intrinsic_name,
|
||||
);
|
||||
}
|
||||
|
@ -264,7 +267,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// Found allocation for both. They must be into the same allocation.
|
||||
if a_alloc_id != b_alloc_id {
|
||||
throw_ub_custom!(
|
||||
fluent::const_eval_different_allocations,
|
||||
fluent::const_eval_offset_from_different_allocations,
|
||||
name = intrinsic_name,
|
||||
);
|
||||
}
|
||||
|
@ -286,7 +289,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// a < b
|
||||
if intrinsic_name == sym::ptr_offset_from_unsigned {
|
||||
throw_ub_custom!(
|
||||
fluent::const_eval_unsigned_offset_from_overflow,
|
||||
fluent::const_eval_offset_from_unsigned_overflow,
|
||||
a_offset = a_offset,
|
||||
b_offset = b_offset,
|
||||
);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
#![feature(strict_provenance)]
|
||||
use core::ptr;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let base = ptr::without_provenance::<()>(10);
|
||||
let unit = &*base;
|
||||
let p1 = unit as *const ();
|
||||
|
||||
let base = ptr::without_provenance::<()>(11);
|
||||
let unit = &*base;
|
||||
let p2 = unit as *const ();
|
||||
|
||||
// Seems to work because they are same pointer
|
||||
// even though it's dangling.
|
||||
let _ = p1.byte_offset_from(p1);
|
||||
|
||||
// UB because different pointers.
|
||||
let _ = p1.byte_offset_from(p2); //~ERROR: different pointers without provenance
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
error: Undefined Behavior: `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation)
|
||||
--> $DIR/ptr_offset_from_different_ints.rs:LL:CC
|
||||
|
|
||||
LL | let _ = p1.byte_offset_from(p2);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on different pointers without provenance (i.e., without an associated 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 $DIR/ptr_offset_from_different_ints.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
|
||||
|
|
@ -42,7 +42,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
|
||||
//~| 0x8[noalloc] is a dangling pointer
|
||||
//~| different pointers without provenance
|
||||
};
|
||||
|
||||
const OUT_OF_BOUNDS_1: isize = {
|
||||
|
@ -81,13 +81,13 @@ pub const DIFFERENT_ALLOC_UNSIGNED: usize = {
|
|||
};
|
||||
|
||||
pub const TOO_FAR_APART1: isize = {
|
||||
let ptr1 = ptr::null::<u8>();
|
||||
let ptr1 = &0u8 as *const u8;
|
||||
let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
|
||||
unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed
|
||||
//~| too far ahead
|
||||
};
|
||||
pub const TOO_FAR_APART2: isize = {
|
||||
let ptr1 = ptr::null::<u8>();
|
||||
let ptr1 = &0u8 as *const u8;
|
||||
let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
|
||||
unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed
|
||||
//~| too far before
|
||||
|
@ -100,7 +100,7 @@ const WRONG_ORDER_UNSIGNED: usize = {
|
|||
//~| first pointer has smaller offset than second: 0 < 8
|
||||
};
|
||||
pub const TOO_FAR_APART_UNSIGNED: usize = {
|
||||
let ptr1 = ptr::null::<u8>();
|
||||
let ptr1 = &0u8 as *const u8;
|
||||
let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
|
||||
// This would fit into a `usize` but we still don't allow it.
|
||||
unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } //~ERROR evaluation of constant value failed
|
||||
|
|
|
@ -33,7 +33,7 @@ error[E0080]: evaluation of constant value failed
|
|||
--> $DIR/offset_from_ub.rs:44:14
|
||||
|
|
||||
LL | unsafe { ptr_offset_from(ptr2, ptr1) }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: 0x8[noalloc] is a dangling pointer (it has no provenance)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation)
|
||||
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/offset_from_ub.rs:53:14
|
||||
|
@ -86,7 +86,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`: null pointer is a dangling pointer (it has no provenance)
|
||||
= note: `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation)
|
||||
|
|
||||
note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
|
||||
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
||||
|
@ -99,7 +99,7 @@ LL | unsafe { ptr2.offset_from(ptr1) }
|
|||
error[E0080]: evaluation of constant value failed
|
||||
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
||||
|
|
||||
= note: out-of-bounds `offset_from`: null pointer is a dangling pointer (it has no provenance)
|
||||
= note: `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation)
|
||||
|
|
||||
note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
|
||||
--> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
||||
|
|
Loading…
Add table
Reference in a new issue