mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
interpret: use AllocRange in UninitByteAccess
also use nice new format string syntax in interpret/error.rs
This commit is contained in:
parent
5b8cf49c51
commit
27b7b3dcd6
@ -427,7 +427,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||||||
err_ub!(DanglingIntPointer(0, _)) =>
|
err_ub!(DanglingIntPointer(0, _)) =>
|
||||||
{ "a null {kind}" },
|
{ "a null {kind}" },
|
||||||
err_ub!(DanglingIntPointer(i, _)) =>
|
err_ub!(DanglingIntPointer(i, _)) =>
|
||||||
{ "a dangling {kind} (address 0x{i:x} is unallocated)" },
|
{ "a dangling {kind} (address {i:#x} is unallocated)" },
|
||||||
err_ub!(PointerOutOfBounds { .. }) =>
|
err_ub!(PointerOutOfBounds { .. }) =>
|
||||||
{ "a dangling {kind} (going beyond the bounds of its allocation)" },
|
{ "a dangling {kind} (going beyond the bounds of its allocation)" },
|
||||||
// This cannot happen during const-eval (because interning already detects
|
// This cannot happen during const-eval (because interning already detects
|
||||||
@ -941,7 +941,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
|
|||||||
// element that byte belongs to so we can
|
// element that byte belongs to so we can
|
||||||
// provide an index.
|
// provide an index.
|
||||||
let i = usize::try_from(
|
let i = usize::try_from(
|
||||||
access.uninit_offset.bytes() / layout.size.bytes(),
|
access.uninit.start.bytes() / layout.size.bytes(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.path.push(PathElem::ArrayElem(i));
|
self.path.push(PathElem::ArrayElem(i));
|
||||||
|
@ -179,6 +179,11 @@ pub fn alloc_range(start: Size, size: Size) -> AllocRange {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AllocRange {
|
impl AllocRange {
|
||||||
|
#[inline]
|
||||||
|
pub fn from(r: Range<Size>) -> Self {
|
||||||
|
alloc_range(r.start, r.end - r.start) // `Size` subtraction (overflow-checked)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn end(self) -> Size {
|
pub fn end(self) -> Size {
|
||||||
self.start + self.size // This does overflow checking.
|
self.start + self.size // This does overflow checking.
|
||||||
@ -1095,9 +1100,9 @@ impl InitMask {
|
|||||||
/// Returns `Ok(())` if it's initialized. Otherwise returns a range of byte
|
/// Returns `Ok(())` if it's initialized. Otherwise returns a range of byte
|
||||||
/// indexes for the first contiguous span of the uninitialized access.
|
/// indexes for the first contiguous span of the uninitialized access.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_range_initialized(&self, start: Size, end: Size) -> Result<(), Range<Size>> {
|
pub fn is_range_initialized(&self, start: Size, end: Size) -> Result<(), AllocRange> {
|
||||||
if end > self.len {
|
if end > self.len {
|
||||||
return Err(self.len..end);
|
return Err(AllocRange::from(self.len..end));
|
||||||
}
|
}
|
||||||
|
|
||||||
let uninit_start = self.find_bit(start, end, false);
|
let uninit_start = self.find_bit(start, end, false);
|
||||||
@ -1105,7 +1110,7 @@ impl InitMask {
|
|||||||
match uninit_start {
|
match uninit_start {
|
||||||
Some(uninit_start) => {
|
Some(uninit_start) => {
|
||||||
let uninit_end = self.find_bit(uninit_start, end, true).unwrap_or(end);
|
let uninit_end = self.find_bit(uninit_start, end, true).unwrap_or(end);
|
||||||
Err(uninit_start..uninit_end)
|
Err(AllocRange::from(uninit_start..uninit_end))
|
||||||
}
|
}
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
}
|
}
|
||||||
@ -1176,19 +1181,17 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
|
|||||||
///
|
///
|
||||||
/// Returns `Ok(())` if it's initialized. Otherwise returns the range of byte
|
/// Returns `Ok(())` if it's initialized. Otherwise returns the range of byte
|
||||||
/// indexes of the first contiguous uninitialized access.
|
/// indexes of the first contiguous uninitialized access.
|
||||||
fn is_init(&self, range: AllocRange) -> Result<(), Range<Size>> {
|
fn is_init(&self, range: AllocRange) -> Result<(), AllocRange> {
|
||||||
self.init_mask.is_range_initialized(range.start, range.end()) // `Size` addition
|
self.init_mask.is_range_initialized(range.start, range.end()) // `Size` addition
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes`
|
/// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes`
|
||||||
/// error which will report the first range of bytes which is uninitialized.
|
/// error which will report the first range of bytes which is uninitialized.
|
||||||
fn check_init(&self, range: AllocRange) -> AllocResult {
|
fn check_init(&self, range: AllocRange) -> AllocResult {
|
||||||
self.is_init(range).map_err(|idx_range| {
|
self.is_init(range).map_err(|uninit_range| {
|
||||||
AllocError::InvalidUninitBytes(Some(UninitBytesAccess {
|
AllocError::InvalidUninitBytes(Some(UninitBytesAccess {
|
||||||
access_offset: range.start,
|
access: range,
|
||||||
access_size: range.size,
|
uninit: uninit_range,
|
||||||
uninit_offset: idx_range.start,
|
|
||||||
uninit_size: idx_range.end - idx_range.start, // `Size` subtraction
|
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{AllocId, ConstAlloc, Pointer, Scalar};
|
use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
|
||||||
|
|
||||||
use crate::mir::interpret::ConstValue;
|
use crate::mir::interpret::ConstValue;
|
||||||
use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree};
|
use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree};
|
||||||
@ -162,9 +162,9 @@ impl fmt::Display for InvalidProgramInfo<'_> {
|
|||||||
AlreadyReported(ErrorGuaranteed { .. }) => {
|
AlreadyReported(ErrorGuaranteed { .. }) => {
|
||||||
write!(f, "encountered constants with type errors, stopping evaluation")
|
write!(f, "encountered constants with type errors, stopping evaluation")
|
||||||
}
|
}
|
||||||
Layout(ref err) => write!(f, "{}", err),
|
Layout(ref err) => write!(f, "{err}"),
|
||||||
FnAbiAdjustForForeignAbi(ref err) => write!(f, "{}", err),
|
FnAbiAdjustForForeignAbi(ref err) => write!(f, "{err}"),
|
||||||
SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{}`", ty),
|
SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{ty}`"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,14 +205,10 @@ impl fmt::Display for CheckInAllocMsg {
|
|||||||
/// Details of an access to uninitialized bytes where it is not allowed.
|
/// Details of an access to uninitialized bytes where it is not allowed.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UninitBytesAccess {
|
pub struct UninitBytesAccess {
|
||||||
/// Location of the original memory access.
|
/// Range of the original memory access.
|
||||||
pub access_offset: Size,
|
pub access: AllocRange,
|
||||||
/// Size of the original memory access.
|
/// Range of the uninit memory that was encountered. (Might not be maximal.)
|
||||||
pub access_size: Size,
|
pub uninit: AllocRange,
|
||||||
/// Location of the first uninitialized byte that was accessed.
|
|
||||||
pub uninit_offset: Size,
|
|
||||||
/// Number of consecutive uninitialized bytes that were accessed.
|
|
||||||
pub uninit_size: Size,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about a size mismatch.
|
/// Information about a size mismatch.
|
||||||
@ -308,30 +304,28 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
use UndefinedBehaviorInfo::*;
|
use UndefinedBehaviorInfo::*;
|
||||||
match self {
|
match self {
|
||||||
Ub(msg) => write!(f, "{}", msg),
|
Ub(msg) => write!(f, "{msg}"),
|
||||||
Unreachable => write!(f, "entering unreachable code"),
|
Unreachable => write!(f, "entering unreachable code"),
|
||||||
BoundsCheckFailed { ref len, ref index } => {
|
BoundsCheckFailed { ref len, ref index } => {
|
||||||
write!(f, "indexing out of bounds: the len is {} but the index is {}", len, index)
|
write!(f, "indexing out of bounds: the len is {len} but the index is {index}")
|
||||||
}
|
}
|
||||||
DivisionByZero => write!(f, "dividing by zero"),
|
DivisionByZero => write!(f, "dividing by zero"),
|
||||||
RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"),
|
RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"),
|
||||||
DivisionOverflow => write!(f, "overflow in signed division (dividing MIN by -1)"),
|
DivisionOverflow => write!(f, "overflow in signed division (dividing MIN by -1)"),
|
||||||
RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"),
|
RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"),
|
||||||
PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
|
PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
|
||||||
InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg),
|
InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {msg}"),
|
||||||
InvalidVtableDropFn(sig) => write!(
|
InvalidVtableDropFn(sig) => write!(
|
||||||
f,
|
f,
|
||||||
"invalid drop function signature: got {}, expected exactly one argument which must be a pointer type",
|
"invalid drop function signature: got {sig}, expected exactly one argument which must be a pointer type",
|
||||||
sig
|
|
||||||
),
|
),
|
||||||
InvalidVtableSize => {
|
InvalidVtableSize => {
|
||||||
write!(f, "invalid vtable: size is bigger than largest supported object")
|
write!(f, "invalid vtable: size is bigger than largest supported object")
|
||||||
}
|
}
|
||||||
InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {}", msg),
|
InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {msg}"),
|
||||||
UnterminatedCString(p) => write!(
|
UnterminatedCString(p) => write!(
|
||||||
f,
|
f,
|
||||||
"reading a null-terminated string starting at {:?} with no null found before end of allocation",
|
"reading a null-terminated string starting at {p:?} with no null found before end of allocation",
|
||||||
p,
|
|
||||||
),
|
),
|
||||||
PointerUseAfterFree(a) => {
|
PointerUseAfterFree(a) => {
|
||||||
write!(f, "pointer to {a:?} was dereferenced after this allocation got freed")
|
write!(f, "pointer to {a:?} was dereferenced after this allocation got freed")
|
||||||
@ -359,41 +353,36 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
|
|||||||
}
|
}
|
||||||
AlignmentCheckFailed { required, has } => write!(
|
AlignmentCheckFailed { required, has } => write!(
|
||||||
f,
|
f,
|
||||||
"accessing memory with alignment {}, but alignment {} is required",
|
"accessing memory with alignment {has}, but alignment {required} is required",
|
||||||
has.bytes(),
|
has = has.bytes(),
|
||||||
required.bytes()
|
required = required.bytes()
|
||||||
),
|
),
|
||||||
WriteToReadOnly(a) => write!(f, "writing to {a:?} which is read-only"),
|
WriteToReadOnly(a) => write!(f, "writing to {a:?} which is read-only"),
|
||||||
DerefFunctionPointer(a) => write!(f, "accessing {a:?} which contains a function"),
|
DerefFunctionPointer(a) => write!(f, "accessing {a:?} which contains a function"),
|
||||||
ValidationFailure { path: None, msg } => {
|
ValidationFailure { path: None, msg } => {
|
||||||
write!(f, "constructing invalid value: {}", msg)
|
write!(f, "constructing invalid value: {msg}")
|
||||||
}
|
}
|
||||||
ValidationFailure { path: Some(path), msg } => {
|
ValidationFailure { path: Some(path), msg } => {
|
||||||
write!(f, "constructing invalid value at {}: {}", path, msg)
|
write!(f, "constructing invalid value at {path}: {msg}")
|
||||||
}
|
}
|
||||||
InvalidBool(b) => {
|
InvalidBool(b) => {
|
||||||
write!(f, "interpreting an invalid 8-bit value as a bool: 0x{:02x}", b)
|
write!(f, "interpreting an invalid 8-bit value as a bool: 0x{b:02x}")
|
||||||
}
|
}
|
||||||
InvalidChar(c) => {
|
InvalidChar(c) => {
|
||||||
write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c)
|
write!(f, "interpreting an invalid 32-bit value as a char: 0x{c:08x}")
|
||||||
}
|
}
|
||||||
InvalidTag(val) => write!(f, "enum value has invalid tag: {:x}", val),
|
InvalidTag(val) => write!(f, "enum value has invalid tag: {val:x}"),
|
||||||
InvalidFunctionPointer(p) => {
|
InvalidFunctionPointer(p) => {
|
||||||
write!(f, "using {:?} as function pointer but it does not point to a function", p)
|
write!(f, "using {p:?} as function pointer but it does not point to a function")
|
||||||
}
|
}
|
||||||
InvalidStr(err) => write!(f, "this string is not valid UTF-8: {}", err),
|
InvalidStr(err) => write!(f, "this string is not valid UTF-8: {err}"),
|
||||||
InvalidUninitBytes(Some((alloc, access))) => write!(
|
InvalidUninitBytes(Some((alloc, info))) => write!(
|
||||||
f,
|
f,
|
||||||
"reading {} byte{} of memory starting at {:?}, \
|
"reading memory at {alloc:?}{access:?}, \
|
||||||
but {} byte{} {} uninitialized starting at {:?}, \
|
but memory is uninitialized at {uninit:?}, \
|
||||||
and this operation requires initialized memory",
|
and this operation requires initialized memory",
|
||||||
access.access_size.bytes(),
|
access = info.access,
|
||||||
pluralize!(access.access_size.bytes()),
|
uninit = info.uninit,
|
||||||
Pointer::new(*alloc, access.access_offset),
|
|
||||||
access.uninit_size.bytes(),
|
|
||||||
pluralize!(access.uninit_size.bytes()),
|
|
||||||
pluralize!("is", access.uninit_size.bytes()),
|
|
||||||
Pointer::new(*alloc, access.uninit_offset),
|
|
||||||
),
|
),
|
||||||
InvalidUninitBytes(None) => write!(
|
InvalidUninitBytes(None) => write!(
|
||||||
f,
|
f,
|
||||||
@ -402,8 +391,7 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
|
|||||||
DeadLocal => write!(f, "accessing a dead local variable"),
|
DeadLocal => write!(f, "accessing a dead local variable"),
|
||||||
ScalarSizeMismatch(self::ScalarSizeMismatch { target_size, data_size }) => write!(
|
ScalarSizeMismatch(self::ScalarSizeMismatch { target_size, data_size }) => write!(
|
||||||
f,
|
f,
|
||||||
"scalar size mismatch: expected {} bytes but got {} bytes instead",
|
"scalar size mismatch: expected {target_size} bytes but got {data_size} bytes instead",
|
||||||
target_size, data_size
|
|
||||||
),
|
),
|
||||||
UninhabitedEnumVariantWritten => {
|
UninhabitedEnumVariantWritten => {
|
||||||
write!(f, "writing discriminant of an uninhabited enum")
|
write!(f, "writing discriminant of an uninhabited enum")
|
||||||
@ -437,13 +425,13 @@ impl fmt::Display for UnsupportedOpInfo {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
use UnsupportedOpInfo::*;
|
use UnsupportedOpInfo::*;
|
||||||
match self {
|
match self {
|
||||||
Unsupported(ref msg) => write!(f, "{}", msg),
|
Unsupported(ref msg) => write!(f, "{msg}"),
|
||||||
ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes"),
|
ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes"),
|
||||||
PartialPointerOverwrite(ptr) => {
|
PartialPointerOverwrite(ptr) => {
|
||||||
write!(f, "unable to overwrite parts of a pointer in memory at {:?}", ptr)
|
write!(f, "unable to overwrite parts of a pointer in memory at {ptr:?}")
|
||||||
}
|
}
|
||||||
ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({:?})", did),
|
ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({did:?})"),
|
||||||
ReadExternStatic(did) => write!(f, "cannot read from extern static ({:?})", did),
|
ReadExternStatic(did) => write!(f, "cannot read from extern static ({did:?})"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -526,11 +514,11 @@ impl fmt::Display for InterpError<'_> {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
use InterpError::*;
|
use InterpError::*;
|
||||||
match *self {
|
match *self {
|
||||||
Unsupported(ref msg) => write!(f, "{}", msg),
|
Unsupported(ref msg) => write!(f, "{msg}"),
|
||||||
InvalidProgram(ref msg) => write!(f, "{}", msg),
|
InvalidProgram(ref msg) => write!(f, "{msg}"),
|
||||||
UndefinedBehavior(ref msg) => write!(f, "{}", msg),
|
UndefinedBehavior(ref msg) => write!(f, "{msg}"),
|
||||||
ResourceExhaustion(ref msg) => write!(f, "{}", msg),
|
ResourceExhaustion(ref msg) => write!(f, "{msg}"),
|
||||||
MachineStop(ref msg) => write!(f, "{}", msg),
|
MachineStop(ref msg) => write!(f, "{msg}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
|
|||||||
--> $DIR/intrinsic-raw_eq-const-padding.rs:6:5
|
--> $DIR/intrinsic-raw_eq-const-padding.rs:6:5
|
||||||
|
|
|
|
||||||
LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16))
|
LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16))
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading 4 bytes of memory starting at alloc3, but 1 byte is uninitialized starting at alloc3+0x1, and this operation requires initialized memory
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at alloc3[0x0..0x4], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user