Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ fn const_validate_mplace<'tcx>(
cid: GlobalId<'tcx>,
) -> Result<(), ErrorHandled> {
let alloc_id = mplace.ptr().provenance.unwrap().alloc_id();
let mut ref_tracking = RefTracking::new(mplace.clone());
let mut ref_tracking = RefTracking::new(mplace.clone(), mplace.layout.ty);
let mut inner = false;
while let Some((mplace, path)) = ref_tracking.next() {
let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) {
Expand Down
91 changes: 55 additions & 36 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ use super::UnsupportedOpInfo::*;
macro_rules! err_validation_failure {
($where:expr, $msg:expr ) => {{
let where_ = &$where;
let path = if !where_.is_empty() {
let path = if !where_.projs.is_empty() {
let mut path = String::new();
write_path(&mut path, where_);
write_path(&mut path, &where_.projs);
Some(path)
} else {
None
Expand All @@ -59,6 +59,7 @@ macro_rules! err_validation_failure {
use ValidationErrorKind::*;
let msg = ValidationErrorKind::from($msg);
err_ub!(ValidationError {
orig_ty: where_.orig_ty,
path,
ptr_bytes_warning: msg.ptr_bytes_warning(),
msg: msg.to_string(),
Expand Down Expand Up @@ -236,7 +237,7 @@ fn fmt_range(r: WrappingRange, max_hi: u128) -> String {
/// So we track a `Vec<PathElem>` where `PathElem` contains all the data we
/// need to later print something for the user.
#[derive(Copy, Clone, Debug)]
pub enum PathElem {
pub enum PathElem<'tcx> {
Field(Symbol),
Variant(Symbol),
CoroutineState(VariantIdx),
Expand All @@ -246,10 +247,22 @@ pub enum PathElem {
Deref,
EnumTag,
CoroutineTag,
DynDowncast,
DynDowncast(Ty<'tcx>),
Vtable,
}

#[derive(Clone, Debug)]
pub struct Path<'tcx> {
orig_ty: Ty<'tcx>,
projs: Vec<PathElem<'tcx>>,
}

impl<'tcx> Path<'tcx> {
fn new(ty: Ty<'tcx>) -> Self {
Self { orig_ty: ty, projs: vec![] }
}
}

/// Extra things to check for during validation of CTFE results.
#[derive(Copy, Clone)]
pub enum CtfeValidationMode {
Expand Down Expand Up @@ -282,16 +295,10 @@ pub struct RefTracking<T, PATH = ()> {
todo: Vec<(T, PATH)>,
}

impl<T: Clone + Eq + Hash + std::fmt::Debug, PATH: Default> RefTracking<T, PATH> {
impl<T: Clone + Eq + Hash + std::fmt::Debug, PATH> RefTracking<T, PATH> {
pub fn empty() -> Self {
RefTracking { seen: FxHashSet::default(), todo: vec![] }
}
pub fn new(val: T) -> Self {
let mut ref_tracking_for_consts =
RefTracking { seen: FxHashSet::default(), todo: vec![(val.clone(), PATH::default())] };
ref_tracking_for_consts.seen.insert(val);
ref_tracking_for_consts
}
pub fn next(&mut self) -> Option<(T, PATH)> {
self.todo.pop()
}
Expand All @@ -306,8 +313,17 @@ impl<T: Clone + Eq + Hash + std::fmt::Debug, PATH: Default> RefTracking<T, PATH>
}
}

impl<'tcx, T: Clone + Eq + Hash + std::fmt::Debug> RefTracking<T, Path<'tcx>> {
pub fn new(val: T, ty: Ty<'tcx>) -> Self {
let mut ref_tracking_for_consts =
RefTracking { seen: FxHashSet::default(), todo: vec![(val.clone(), Path::new(ty))] };
ref_tracking_for_consts.seen.insert(val);
ref_tracking_for_consts
}
}

/// Format a path
fn write_path(out: &mut String, path: &[PathElem]) {
fn write_path(out: &mut String, path: &[PathElem<'_>]) {
use self::PathElem::*;

for elem in path.iter() {
Expand All @@ -325,7 +341,7 @@ fn write_path(out: &mut String, path: &[PathElem]) {
// even use the usual syntax because we are just showing the projections,
// not the root.
Deref => write!(out, ".<deref>"),
DynDowncast => write!(out, ".<dyn-downcast>"),
DynDowncast(ty) => write!(out, ".<dyn-downcast({ty})>"),
Vtable => write!(out, ".<vtable>"),
}
.unwrap()
Expand Down Expand Up @@ -384,10 +400,9 @@ impl RangeSet {

struct ValidityVisitor<'rt, 'tcx, M: Machine<'tcx>> {
/// The `path` may be pushed to, but the part that is present when a function
/// starts must not be changed! `visit_fields` and `visit_array` rely on
/// this stack discipline.
path: Vec<PathElem>,
ref_tracking: Option<&'rt mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Vec<PathElem>>>,
/// starts must not be changed! `with_elem` relies on this stack discipline.
path: Path<'tcx>,
ref_tracking: Option<&'rt mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Path<'tcx>>>,
/// `None` indicates this is not validating for CTFE (but for runtime).
ctfe_mode: Option<CtfeValidationMode>,
ecx: &'rt mut InterpCx<'tcx, M>,
Expand All @@ -406,7 +421,12 @@ struct ValidityVisitor<'rt, 'tcx, M: Machine<'tcx>> {
}

impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) -> PathElem {
fn aggregate_field_path_elem(
&mut self,
layout: TyAndLayout<'tcx>,
field: usize,
field_ty: Ty<'tcx>,
) -> PathElem<'tcx> {
// First, check if we are projecting to a variant.
match layout.variants {
Variants::Multiple { tag_field, .. } => {
Expand Down Expand Up @@ -476,7 +496,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
// dyn traits
ty::Dynamic(..) => {
assert_eq!(field, 0);
PathElem::DynDowncast
PathElem::DynDowncast(field_ty)
}

// nothing else has an aggregate layout
Expand All @@ -486,17 +506,17 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {

fn with_elem<R>(
&mut self,
elem: PathElem,
elem: PathElem<'tcx>,
f: impl FnOnce(&mut Self) -> InterpResult<'tcx, R>,
) -> InterpResult<'tcx, R> {
// Remember the old state
let path_len = self.path.len();
let path_len = self.path.projs.len();
// Record new element
self.path.push(elem);
self.path.projs.push(elem);
// Perform operation
let r = f(self)?;
// Undo changes
self.path.truncate(path_len);
self.path.projs.truncate(path_len);
// Done
interp_ok(r)
}
Expand Down Expand Up @@ -795,10 +815,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
ref_tracking.track(place, || {
// We need to clone the path anyway, make sure it gets created
// with enough space for the additional `Deref`.
let mut new_path = Vec::with_capacity(path.len() + 1);
new_path.extend(path);
new_path.push(PathElem::Deref);
new_path
let mut new_projs = Vec::with_capacity(path.projs.len() + 1);
new_projs.extend(&path.projs);
new_projs.push(PathElem::Deref);
Path { projs: new_projs, orig_ty: path.orig_ty }
});
}
interp_ok(())
Expand Down Expand Up @@ -1219,7 +1239,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
field: usize,
new_val: &PlaceTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx> {
let elem = self.aggregate_field_path_elem(old_val.layout, field);
let elem = self.aggregate_field_path_elem(old_val.layout, field, new_val.layout.ty);
self.with_elem(elem, move |this| this.visit_value(new_val))
}

Expand Down Expand Up @@ -1384,7 +1404,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
access.bad.start.bytes() / layout.size.bytes(),
)
.unwrap();
self.path.push(PathElem::ArrayElem(i));
self.path.projs.push(PathElem::ArrayElem(i));

if matches!(kind, Ub(InvalidUninitBytes(_))) {
err_validation_failure!(self.path, Uninit { expected })
Expand Down Expand Up @@ -1511,8 +1531,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
fn validate_operand_internal(
&mut self,
val: &PlaceTy<'tcx, M::Provenance>,
path: Vec<PathElem>,
ref_tracking: Option<&mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Vec<PathElem>>>,
path: Path<'tcx>,
ref_tracking: Option<&mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Path<'tcx>>>,
ctfe_mode: Option<CtfeValidationMode>,
reset_provenance_and_padding: bool,
) -> InterpResult<'tcx> {
Expand Down Expand Up @@ -1565,8 +1585,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
pub(crate) fn const_validate_operand(
&mut self,
val: &PlaceTy<'tcx, M::Provenance>,
path: Vec<PathElem>,
ref_tracking: &mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Vec<PathElem>>,
path: Path<'tcx>,
ref_tracking: &mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Path<'tcx>>,
ctfe_mode: CtfeValidationMode,
) -> InterpResult<'tcx> {
self.validate_operand_internal(
Expand Down Expand Up @@ -1595,14 +1615,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
reset_provenance_and_padding,
?val,
);

// Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's
// still correct to not use `ctfe_mode`: that mode is for validation of the final constant
// value, it rules out things like `UnsafeCell` in awkward places.
if !recursive {
return self.validate_operand_internal(
val,
vec![],
Path::new(val.layout.ty),
None,
None,
reset_provenance_and_padding,
Expand All @@ -1612,7 +1631,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let mut ref_tracking = RefTracking::empty();
self.validate_operand_internal(
val,
vec![],
Path::new(val.layout.ty),
Some(&mut ref_tracking),
None,
reset_provenance_and_padding,
Expand Down
15 changes: 10 additions & 5 deletions compiler/rustc_middle/src/mir/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,12 @@ pub enum UndefinedBehaviorInfo<'tcx> {
/// Free-form case. Only for errors that are never caught! Used by miri
Ub(String),
/// Validation error.
ValidationError { path: Option<String>, msg: String, ptr_bytes_warning: bool },
ValidationError {
orig_ty: Ty<'tcx>,
path: Option<String>,
msg: String,
ptr_bytes_warning: bool,
},

/// Unreachable code was executed.
Unreachable,
Expand Down Expand Up @@ -457,11 +462,11 @@ impl<'tcx> fmt::Display for UndefinedBehaviorInfo<'tcx> {
match self {
Ub(msg) => write!(f, "{msg}"),

ValidationError { path: None, msg, .. } => {
write!(f, "constructing invalid value: {msg}")
ValidationError { orig_ty, path: None, msg, .. } => {
write!(f, "constructing invalid value of type {orig_ty}: {msg}")
}
ValidationError { path: Some(path), msg, .. } => {
write!(f, "constructing invalid value at {path}: {msg}")
ValidationError { orig_ty, path: Some(path), msg, .. } => {
write!(f, "constructing invalid value of type {orig_ty}: at {path}, {msg}")
}

Unreachable => write!(f, "entering unreachable code"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value at [3]: encountered uninitialized memory, but expected an integer
error: Undefined Behavior: constructing invalid value of type [u8; 4]: at [3], encountered uninitialized memory, but expected an integer
--> tests/fail-dep/libc/libc-read-and-uninit-premature-eof.rs:LL:CC
|
LL | buf.assume_init();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn main() {
// However, it drops provenance when transmuting to TwoPtrs, so this is UB.
let val = unsafe {
transmute::<_, &str>(
//~^ ERROR: constructing invalid value: encountered a dangling reference
//~^ ERROR: encountered a dangling reference
!mask & transmute::<_, TwoPtrs>("false !")
| mask & transmute::<_, TwoPtrs>("true !"),
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance)
error: Undefined Behavior: constructing invalid value of type &str: encountered a dangling reference ($HEX[noalloc] has no provenance)
--> tests/fail/branchless-select-i128-pointer.rs:LL:CC
|
LL | / transmute::<_, &str>(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: encountered a dangling box (0x18[noalloc] has no provenance)
error: Undefined Behavior: constructing invalid value of type std::boxed::Box<i32>: encountered a dangling box (0x18[noalloc] has no provenance)
--> tests/fail/dangling_pointers/deref_dangling_box.rs:LL:CC
|
LL | let _val = unsafe { addr_of_mut!(**outer) };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: encountered a dangling reference (0x18[noalloc] has no provenance)
error: Undefined Behavior: constructing invalid value of type &mut i32: encountered a dangling reference (0x18[noalloc] has no provenance)
--> tests/fail/dangling_pointers/deref_dangling_ref.rs:LL:CC
|
LL | let _val = unsafe { addr_of_mut!(**outer) };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation)
error: Undefined Behavior: constructing invalid value of type &SliceWithHead: encountered a dangling reference (going beyond the bounds of its allocation)
--> tests/fail/dangling_pointers/dyn_size.rs:LL:CC
|
LL | let _ptr = unsafe { &*ptr };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug + std::marker::Send + std::marker::Sync`, but encountered `std::fmt::Display`
error: Undefined Behavior: constructing invalid value of type *const dyn std::fmt::Debug + std::marker::Send + std::marker::Sync: wrong trait in wide pointer vtable: expected `std::fmt::Debug + std::marker::Send + std::marker::Sync`, but encountered `std::fmt::Display`
--> tests/fail/dyn-upcast-nop-wrong-trait.rs:LL:CC
|
LL | let ptr: *const (dyn fmt::Debug + Send + Sync) = unsafe { std::mem::transmute(ptr) };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value at [0]: encountered 0x02, but expected a boolean
error: Undefined Behavior: constructing invalid value of type [bool; 100]: at [0], encountered 0x02, but expected a boolean
--> tests/fail/intrinsics/typed-swap-invalid-array.rs:LL:CC
|
LL | typed_swap_nonoverlapping(a, b);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: encountered 0x02, but expected a boolean
error: Undefined Behavior: constructing invalid value of type bool: encountered 0x02, but expected a boolean
--> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC
|
LL | typed_swap_nonoverlapping(a, b);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: encountered 0x03, but expected a boolean
error: Undefined Behavior: constructing invalid value of type bool: encountered 0x03, but expected a boolean
--> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC
|
LL | typed_swap_nonoverlapping(a, b);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: encountered a value of the never type `!`
error: Undefined Behavior: constructing invalid value of type !: encountered a value of the never type `!`
--> tests/fail/intrinsics/uninit_uninhabited_type.rs:LL:CC
|
LL | let _ = unsafe { std::mem::uninitialized::<!>() };
Expand Down
2 changes: 1 addition & 1 deletion src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: encountered a null function pointer
error: Undefined Behavior: constructing invalid value of type fn(): encountered a null function pointer
--> tests/fail/intrinsics/zero_fn_ptr.rs:LL:CC
|
LL | let _ = unsafe { std::mem::zeroed::<fn()>() };
Expand Down
2 changes: 1 addition & 1 deletion src/tools/miri/tests/fail/issue-miri-1112.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: encountered $HEX[ALLOC]<TAG>, but expected a vtable pointer
error: Undefined Behavior: constructing invalid value of type *mut FunnyPointer: encountered $HEX[ALLOC]<TAG>, but expected a vtable pointer
--> tests/fail/issue-miri-1112.rs:LL:CC
|
LL | let obj = std::mem::transmute::<FatPointer, *mut FunnyPointer>(obj);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free)
error: Undefined Behavior: constructing invalid value of type &u32: encountered a dangling reference (use-after-free)
--> tests/fail/match/closures/deref-in-pattern.rs:LL:CC
|
LL | let _ = || {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free)
error: Undefined Behavior: constructing invalid value of type &u32: encountered a dangling reference (use-after-free)
--> tests/fail/match/closures/partial-pattern.rs:LL:CC
|
LL | let _ = || {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance)
error: Undefined Behavior: constructing invalid value of type &i32: encountered a dangling reference ($HEX[noalloc] has no provenance)
--> tests/fail/provenance/int_copy_looses_provenance0.rs:LL:CC
|
LL | let _val = unsafe { *ptr.read() };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance)
error: Undefined Behavior: constructing invalid value of type &i32: encountered a dangling reference ($HEX[noalloc] has no provenance)
--> tests/fail/provenance/int_copy_looses_provenance1.rs:LL:CC
|
LL | let _val = unsafe { *ptr.read() };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance)
error: Undefined Behavior: constructing invalid value of type &i32: encountered a dangling reference ($HEX[noalloc] has no provenance)
--> tests/fail/provenance/int_copy_looses_provenance2.rs:LL:CC
|
LL | let _val = unsafe { *ptr.read() };
Expand Down
2 changes: 1 addition & 1 deletion src/tools/miri/tests/fail/storage-live-resets-var.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: encountered uninitialized memory, but expected an integer
error: Undefined Behavior: constructing invalid value of type i32: encountered uninitialized memory, but expected an integer
--> tests/fail/storage-live-resets-var.rs:LL:CC
|
LL | _val2 = val;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN)
error: Undefined Behavior: constructing invalid value of type &mut PartialDrop: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN)
--> RUSTLIB/core/src/ptr/mod.rs:LL:CC
|
LL | / pub const unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T)
Expand Down
Loading
Loading