Skip to content

Commit 1a56ec4

Browse files
committed
Auto merge of #59627 - LooMaclin:issue_57128_improve_miri_error_reporting_in_check_in_alloc, r=RalfJung
Improve miri error reporting in check_in_alloc Fixes #57128 r? @RalfJung @oli-obk
2 parents 4dbc7f9 + 9e643e6 commit 1a56ec4

File tree

7 files changed

+54
-30
lines changed

7 files changed

+54
-30
lines changed

src/librustc/mir/interpret/allocation.rs

+32-7
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use super::{
77

88
use crate::ty::layout::{Size, Align};
99
use syntax::ast::Mutability;
10-
use std::iter;
10+
use std::{iter, fmt::{self, Display}};
1111
use crate::mir;
1212
use std::ops::{Deref, DerefMut};
1313
use rustc_data_structures::sorted_map::SortedMap;
@@ -22,6 +22,28 @@ pub enum InboundsCheck {
2222
MaybeDead,
2323
}
2424

25+
/// Used by `check_in_alloc` to indicate context of check
26+
#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
27+
pub enum CheckInAllocMsg {
28+
MemoryAccessTest,
29+
NullPointerTest,
30+
PointerArithmeticTest,
31+
InboundsTest,
32+
}
33+
34+
impl Display for CheckInAllocMsg {
35+
/// When this is printed as an error the context looks like this
36+
/// "{test name} failed: pointer must be in-bounds at offset..."
37+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38+
write!(f, "{}", match *self {
39+
CheckInAllocMsg::MemoryAccessTest => "Memory access",
40+
CheckInAllocMsg::NullPointerTest => "Null pointer test",
41+
CheckInAllocMsg::PointerArithmeticTest => "Pointer arithmetic",
42+
CheckInAllocMsg::InboundsTest => "Inbounds test",
43+
})
44+
}
45+
}
46+
2547
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
2648
pub struct Allocation<Tag=(),Extra=()> {
2749
/// The actual bytes of the allocation.
@@ -131,9 +153,10 @@ impl<'tcx, Tag, Extra> Allocation<Tag, Extra> {
131153
fn check_bounds_ptr(
132154
&self,
133155
ptr: Pointer<Tag>,
156+
msg: CheckInAllocMsg,
134157
) -> EvalResult<'tcx> {
135158
let allocation_size = self.bytes.len() as u64;
136-
ptr.check_in_alloc(Size::from_bytes(allocation_size), InboundsCheck::Live)
159+
ptr.check_in_alloc(Size::from_bytes(allocation_size), msg)
137160
}
138161

139162
/// Checks if the memory range beginning at `ptr` and of size `Size` is "in-bounds".
@@ -143,9 +166,10 @@ impl<'tcx, Tag, Extra> Allocation<Tag, Extra> {
143166
cx: &impl HasDataLayout,
144167
ptr: Pointer<Tag>,
145168
size: Size,
169+
msg: CheckInAllocMsg,
146170
) -> EvalResult<'tcx> {
147171
// if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
148-
self.check_bounds_ptr(ptr.offset(size, cx)?)
172+
self.check_bounds_ptr(ptr.offset(size, cx)?, msg)
149173
}
150174
}
151175

@@ -164,9 +188,10 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
164188
ptr: Pointer<Tag>,
165189
size: Size,
166190
check_defined_and_ptr: bool,
191+
msg: CheckInAllocMsg,
167192
) -> EvalResult<'tcx, &[u8]>
168193
{
169-
self.check_bounds(cx, ptr, size)?;
194+
self.check_bounds(cx, ptr, size, msg)?;
170195

171196
if check_defined_and_ptr {
172197
self.check_defined(ptr, size)?;
@@ -192,7 +217,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
192217
size: Size,
193218
) -> EvalResult<'tcx, &[u8]>
194219
{
195-
self.get_bytes_internal(cx, ptr, size, true)
220+
self.get_bytes_internal(cx, ptr, size, true, CheckInAllocMsg::MemoryAccessTest)
196221
}
197222

198223
/// It is the caller's responsibility to handle undefined and pointer bytes.
@@ -205,7 +230,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
205230
size: Size,
206231
) -> EvalResult<'tcx, &[u8]>
207232
{
208-
self.get_bytes_internal(cx, ptr, size, false)
233+
self.get_bytes_internal(cx, ptr, size, false, CheckInAllocMsg::MemoryAccessTest)
209234
}
210235

211236
/// Just calling this already marks everything as defined and removes relocations,
@@ -218,7 +243,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
218243
) -> EvalResult<'tcx, &mut [u8]>
219244
{
220245
assert_ne!(size.bytes(), 0, "0-sized accesses should never even get a `Pointer`");
221-
self.check_bounds(cx, ptr, size)?;
246+
self.check_bounds(cx, ptr, size, CheckInAllocMsg::MemoryAccessTest)?;
222247

223248
self.mark_definedness(ptr, size, true)?;
224249
self.clear_relocations(cx, ptr, size)?;

src/librustc/mir/interpret/error.rs

+6-10
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::ty::layout::{Size, Align, LayoutError};
88
use rustc_target::spec::abi::Abi;
99
use rustc_macros::HashStable;
1010

11-
use super::{RawConst, Pointer, InboundsCheck, ScalarMaybeUndef};
11+
use super::{RawConst, Pointer, CheckInAllocMsg, ScalarMaybeUndef};
1212

1313
use backtrace::Backtrace;
1414

@@ -247,7 +247,7 @@ pub enum InterpError<'tcx, O> {
247247
InvalidDiscriminant(ScalarMaybeUndef),
248248
PointerOutOfBounds {
249249
ptr: Pointer,
250-
check: InboundsCheck,
250+
msg: CheckInAllocMsg,
251251
allocation_size: Size,
252252
},
253253
InvalidNullPointerUsage,
@@ -466,14 +466,10 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for InterpError<'tcx, O> {
466466
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
467467
use self::InterpError::*;
468468
match *self {
469-
PointerOutOfBounds { ptr, check, allocation_size } => {
470-
write!(f, "Pointer must be in-bounds{} at offset {}, but is outside bounds of \
471-
allocation {} which has size {}",
472-
match check {
473-
InboundsCheck::Live => " and live",
474-
InboundsCheck::MaybeDead => "",
475-
},
476-
ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes())
469+
PointerOutOfBounds { ptr, msg, allocation_size } => {
470+
write!(f, "{} failed: pointer must be in-bounds at offset {}, \
471+
but is outside bounds of allocation {} which has size {}",
472+
msg, ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes())
477473
},
478474
ValidationFailure(ref err) => {
479475
write!(f, "type validation failed: {}", err)

src/librustc/mir/interpret/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub use self::value::{Scalar, ScalarMaybeUndef, RawConst, ConstValue};
1919

2020
pub use self::allocation::{
2121
InboundsCheck, Allocation, AllocationExtra,
22-
Relocations, UndefMask,
22+
Relocations, UndefMask, CheckInAllocMsg,
2323
};
2424

2525
pub use self::pointer::{Pointer, PointerArithmetic};

src/librustc/mir/interpret/pointer.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::ty::layout::{self, HasDataLayout, Size};
55
use rustc_macros::HashStable;
66

77
use super::{
8-
AllocId, EvalResult, InboundsCheck,
8+
AllocId, EvalResult, CheckInAllocMsg
99
};
1010

1111
////////////////////////////////////////////////////////////////////////////////
@@ -177,12 +177,12 @@ impl<'tcx, Tag> Pointer<Tag> {
177177
pub fn check_in_alloc(
178178
self,
179179
allocation_size: Size,
180-
check: InboundsCheck,
180+
msg: CheckInAllocMsg,
181181
) -> EvalResult<'tcx, ()> {
182182
if self.offset > allocation_size {
183183
err!(PointerOutOfBounds {
184184
ptr: self.erase_tag(),
185-
check,
185+
msg,
186186
allocation_size,
187187
})
188188
} else {

src/librustc_mir/interpret/memory.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use syntax::ast::Mutability;
2020
use super::{
2121
Pointer, AllocId, Allocation, GlobalId, AllocationExtra,
2222
EvalResult, Scalar, InterpError, AllocKind, PointerArithmetic,
23-
Machine, AllocMap, MayLeak, ErrorHandled, InboundsCheck,
23+
Machine, AllocMap, MayLeak, ErrorHandled, CheckInAllocMsg, InboundsCheck,
2424
};
2525

2626
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
@@ -252,7 +252,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
252252
Scalar::Ptr(ptr) => {
253253
// check this is not NULL -- which we can ensure only if this is in-bounds
254254
// of some (potentially dead) allocation.
255-
let align = self.check_bounds_ptr(ptr, InboundsCheck::MaybeDead)?;
255+
let align = self.check_bounds_ptr(ptr, InboundsCheck::MaybeDead,
256+
CheckInAllocMsg::NullPointerTest)?;
256257
(ptr.offset.bytes(), align)
257258
}
258259
Scalar::Bits { bits, size } => {
@@ -293,9 +294,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
293294
&self,
294295
ptr: Pointer<M::PointerTag>,
295296
liveness: InboundsCheck,
297+
msg: CheckInAllocMsg,
296298
) -> EvalResult<'tcx, Align> {
297299
let (allocation_size, align) = self.get_size_and_align(ptr.alloc_id, liveness)?;
298-
ptr.check_in_alloc(allocation_size, liveness)?;
300+
ptr.check_in_alloc(allocation_size, msg)?;
299301
Ok(align)
300302
}
301303
}
@@ -419,7 +421,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
419421

420422
/// Obtain the size and alignment of an allocation, even if that allocation has been deallocated
421423
///
422-
/// If `liveness` is `InboundsCheck::Dead`, this function always returns `Ok`
424+
/// If `liveness` is `InboundsCheck::MaybeDead`, this function always returns `Ok`
423425
pub fn get_size_and_align(
424426
&self,
425427
id: AllocId,

src/librustc_mir/interpret/operand.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ use rustc::{mir, ty};
77
use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt, VariantIdx};
88

99
use rustc::mir::interpret::{
10-
GlobalId, AllocId, InboundsCheck,
10+
GlobalId, AllocId, CheckInAllocMsg,
1111
ConstValue, Pointer, Scalar,
12-
EvalResult, InterpError,
12+
EvalResult, InterpError, InboundsCheck,
1313
sign_extend, truncate,
1414
};
1515
use super::{
@@ -645,7 +645,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
645645
ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) => {
646646
// The niche must be just 0 (which an inbounds pointer value never is)
647647
let ptr_valid = niche_start == 0 && variants_start == variants_end &&
648-
self.memory.check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok();
648+
self.memory.check_bounds_ptr(ptr, InboundsCheck::MaybeDead,
649+
CheckInAllocMsg::NullPointerTest).is_ok();
649650
if !ptr_valid {
650651
return err!(InvalidDiscriminant(raw_discr.erase_tag()));
651652
}

src/librustc_mir/interpret/validity.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf, VariantIdx};
88
use rustc::ty;
99
use rustc_data_structures::fx::FxHashSet;
1010
use rustc::mir::interpret::{
11-
Scalar, AllocKind, EvalResult, InterpError,
11+
Scalar, AllocKind, EvalResult, InterpError, CheckInAllocMsg,
1212
};
1313

1414
use super::{
@@ -417,7 +417,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
417417
try_validation!(
418418
self.ecx.memory
419419
.get(ptr.alloc_id)?
420-
.check_bounds(self.ecx, ptr, size),
420+
.check_bounds(self.ecx, ptr, size, CheckInAllocMsg::InboundsTest),
421421
"dangling (not entirely in bounds) reference", self.path);
422422
}
423423
// Check if we have encountered this pointer+layout combination

0 commit comments

Comments
 (0)