Skip to content

Commit d9943e9

Browse files
committed
validation: descend from consts into statics
1 parent 60b12fd commit d9943e9

25 files changed

+318
-208
lines changed

compiler/rustc_const_eval/messages.ftl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,6 @@ const_eval_modified_global =
215215
const_eval_mut_deref =
216216
mutation through a reference is not allowed in {const_eval_const_context}s
217217
218-
const_eval_mutable_data_in_const =
219-
constant refers to mutable data
220-
221218
const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind}
222219
223220
const_eval_non_const_fmt_macro_call =
@@ -414,6 +411,9 @@ const_eval_upcast_mismatch =
414411
## (We'd love to sort this differently to make that more clear but tidy won't let us...)
415412
const_eval_validation_box_to_static = {$front_matter}: encountered a box pointing to a static variable in a constant
416413
const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty}
414+
415+
const_eval_validation_const_ref_to_mutable = {$front_matter}: encountered reference to mutable memory in `const`
416+
417417
const_eval_validation_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance)
418418
const_eval_validation_dangling_box_out_of_bounds = {$front_matter}: encountered a dangling box (going beyond the bounds of its allocation)
419419
const_eval_validation_dangling_box_use_after_free = {$front_matter}: encountered a dangling box (use-after-free)

compiler/rustc_const_eval/src/const_eval/mod.rs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
// Not in interpret to make sure we do not use private implementation details
22

3-
use crate::interpret::InterpCx;
43
use rustc_middle::mir;
5-
use rustc_middle::mir::interpret::{InterpError, InterpErrorInfo};
4+
use rustc_middle::mir::interpret::InterpErrorInfo;
65
use rustc_middle::query::TyCtxtAt;
76
use rustc_middle::ty::{self, Ty};
87

8+
use crate::interpret::{format_interp_error, InterpCx};
9+
910
mod error;
1011
mod eval_queries;
1112
mod fn_queries;
@@ -25,24 +26,17 @@ pub(crate) enum ValTreeCreationError {
2526
NodesOverflow,
2627
/// Values of this type, or this particular value, are not supported as valtrees.
2728
NonSupportedType,
28-
/// The value pointed to non-read-only memory, so we cannot make it a valtree.
29-
NotReadOnly,
30-
Other,
3129
}
3230
pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError>;
3331

3432
impl From<InterpErrorInfo<'_>> for ValTreeCreationError {
3533
fn from(err: InterpErrorInfo<'_>) -> Self {
36-
match err.kind() {
37-
InterpError::MachineStop(err) => {
38-
let err = err.downcast_ref::<ConstEvalErrKind>().unwrap();
39-
match err {
40-
ConstEvalErrKind::ConstAccessesMutGlobal => ValTreeCreationError::NotReadOnly,
41-
_ => ValTreeCreationError::Other,
42-
}
43-
}
44-
_ => ValTreeCreationError::Other,
45-
}
34+
ty::tls::with(|tcx| {
35+
bug!(
36+
"Unexpected Undefined Behavior error during valtree construction: {}",
37+
format_interp_error(tcx.dcx(), err),
38+
)
39+
})
4640
}
4741
}
4842

compiler/rustc_const_eval/src/const_eval/valtrees.rs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use super::eval_queries::{mk_eval_cx, op_to_const};
99
use super::machine::CompileTimeEvalContext;
1010
use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES};
1111
use crate::const_eval::CanAccessMutGlobal;
12-
use crate::errors::{MaxNumNodesInConstErr, MutableDataInConstErr};
12+
use crate::errors::MaxNumNodesInConstErr;
1313
use crate::interpret::MPlaceTy;
1414
use crate::interpret::{
1515
intern_const_alloc_recursive, ImmTy, Immediate, InternKind, MemPlaceMeta, MemoryKind, PlaceTy,
@@ -248,18 +248,6 @@ pub(crate) fn eval_to_valtree<'tcx>(
248248
tcx.dcx().emit_err(MaxNumNodesInConstErr { span, global_const_id });
249249
Err(handled.into())
250250
}
251-
ValTreeCreationError::NotReadOnly => {
252-
let handled =
253-
tcx.dcx().emit_err(MutableDataInConstErr { span, global_const_id });
254-
Err(handled.into())
255-
}
256-
ValTreeCreationError::Other => {
257-
let handled = tcx.dcx().span_delayed_bug(
258-
span.unwrap_or(DUMMY_SP),
259-
"unexpected error during valtree construction",
260-
);
261-
Err(handled.into())
262-
}
263251
ValTreeCreationError::NonSupportedType => Ok(None),
264252
}
265253
}

compiler/rustc_const_eval/src/errors.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,6 @@ pub(crate) struct MaxNumNodesInConstErr {
117117
pub global_const_id: String,
118118
}
119119

120-
#[derive(Diagnostic)]
121-
#[diag(const_eval_mutable_data_in_const)]
122-
pub(crate) struct MutableDataInConstErr {
123-
#[primary_span]
124-
pub span: Option<Span>,
125-
pub global_const_id: String,
126-
}
127-
128120
#[derive(Diagnostic)]
129121
#[diag(const_eval_unallowed_fn_pointer_call)]
130122
pub(crate) struct UnallowedFnPointerCall {
@@ -619,6 +611,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
619611

620612
PointerAsInt { .. } => const_eval_validation_pointer_as_int,
621613
PartialPointer => const_eval_validation_partial_pointer,
614+
ConstRefToMutable => const_eval_validation_const_ref_to_mutable,
622615
MutableRefInConst => const_eval_validation_mutable_ref_in_const,
623616
MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
624617
NullFnPtr => const_eval_validation_null_fn_ptr,
@@ -773,6 +766,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
773766
NullPtr { .. }
774767
| PtrToStatic { .. }
775768
| MutableRefInConst
769+
| ConstRefToMutable
776770
| MutableRefToImmutable
777771
| NullFnPtr
778772
| NeverVal

compiler/rustc_const_eval/src/interpret/eval_context.rs

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::{fmt, mem};
44
use either::{Either, Left, Right};
55

66
use hir::CRATE_HIR_ID;
7+
use rustc_errors::DiagCtxt;
78
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
89
use rustc_index::IndexVec;
910
use rustc_middle::mir;
@@ -430,6 +431,26 @@ pub(super) fn from_known_layout<'tcx>(
430431
}
431432
}
432433

434+
/// Turn the given error into a human-readable string. Expects the string to be printed, so if
435+
/// `RUSTC_CTFE_BACKTRACE` is set this will show a backtrace of the rustc internals that
436+
/// triggered the error.
437+
///
438+
/// This is NOT the preferred way to render an error; use `report` from `const_eval` instead.
439+
/// However, this is useful when error messages appear in ICEs.
440+
pub fn format_interp_error<'tcx>(dcx: &DiagCtxt, e: InterpErrorInfo<'tcx>) -> String {
441+
let (e, backtrace) = e.into_parts();
442+
backtrace.print_backtrace();
443+
// FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the
444+
// label and arguments from the InterpError.
445+
#[allow(rustc::untranslatable_diagnostic)]
446+
let mut diag = dcx.struct_allow("");
447+
let msg = e.diagnostic_message();
448+
e.add_args(dcx, &mut diag);
449+
let s = dcx.eagerly_translate_to_string(msg, diag.args());
450+
diag.cancel();
451+
s
452+
}
453+
433454
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
434455
pub fn new(
435456
tcx: TyCtxt<'tcx>,
@@ -462,27 +483,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
462483
.map_or(CRATE_HIR_ID, |def_id| self.tcx.local_def_id_to_hir_id(def_id))
463484
}
464485

465-
/// Turn the given error into a human-readable string. Expects the string to be printed, so if
466-
/// `RUSTC_CTFE_BACKTRACE` is set this will show a backtrace of the rustc internals that
467-
/// triggered the error.
468-
///
469-
/// This is NOT the preferred way to render an error; use `report` from `const_eval` instead.
470-
/// However, this is useful when error messages appear in ICEs.
471-
pub fn format_error(&self, e: InterpErrorInfo<'tcx>) -> String {
472-
let (e, backtrace) = e.into_parts();
473-
backtrace.print_backtrace();
474-
// FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the
475-
// label and arguments from the InterpError.
476-
let dcx = self.tcx.dcx();
477-
#[allow(rustc::untranslatable_diagnostic)]
478-
let mut diag = dcx.struct_allow("");
479-
let msg = e.diagnostic_message();
480-
e.add_args(dcx, &mut diag);
481-
let s = dcx.eagerly_translate_to_string(msg, diag.args());
482-
diag.cancel();
483-
s
484-
}
485-
486486
#[inline(always)]
487487
pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>] {
488488
M::stack(self)

compiler/rustc_const_eval/src/interpret/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ mod visitor;
2020

2121
pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here
2222

23-
pub use self::eval_context::{Frame, FrameInfo, InterpCx, StackPopCleanup};
23+
pub use self::eval_context::{format_interp_error, Frame, FrameInfo, InterpCx, StackPopCleanup};
2424
pub use self::intern::{
2525
intern_const_alloc_for_constprop, intern_const_alloc_recursive, InternKind,
2626
};

compiler/rustc_const_eval/src/interpret/validity.rs

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ use rustc_target::abi::{
2727
use std::hash::Hash;
2828

2929
use super::{
30-
AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy,
31-
Machine, MemPlaceMeta, OpTy, Pointer, Projectable, Scalar, ValueVisitor,
30+
format_interp_error, AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx,
31+
InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Pointer, Projectable, Scalar,
32+
ValueVisitor,
3233
};
3334

3435
// for the validation errors
@@ -460,46 +461,49 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
460461
// Special handling for pointers to statics (irrespective of their type).
461462
assert!(!self.ecx.tcx.is_thread_local_static(did));
462463
assert!(self.ecx.tcx.is_static(did));
464+
let is_mut =
465+
matches!(self.ecx.tcx.def_kind(did), DefKind::Static(Mutability::Mut))
466+
|| !self
467+
.ecx
468+
.tcx
469+
.type_of(did)
470+
.no_bound_vars()
471+
.expect("statics should not have generic parameters")
472+
.is_freeze(*self.ecx.tcx, ty::ParamEnv::reveal_all());
463473
// Mutability check.
464474
if ptr_expected_mutbl == Mutability::Mut {
465-
if matches!(
466-
self.ecx.tcx.def_kind(did),
467-
DefKind::Static(Mutability::Not)
468-
) && self
469-
.ecx
470-
.tcx
471-
.type_of(did)
472-
.no_bound_vars()
473-
.expect("statics should not have generic parameters")
474-
.is_freeze(*self.ecx.tcx, ty::ParamEnv::reveal_all())
475-
{
475+
if !is_mut {
476476
throw_validation_failure!(self.path, MutableRefToImmutable);
477477
}
478478
}
479-
// We skip recursively checking other statics. These statics must be sound by
480-
// themselves, and the only way to get broken statics here is by using
481-
// unsafe code.
482-
// The reasons we don't check other statics is twofold. For one, in all
483-
// sound cases, the static was already validated on its own, and second, we
484-
// trigger cycle errors if we try to compute the value of the other static
485-
// and that static refers back to us.
486-
// We might miss const-invalid data,
487-
// but things are still sound otherwise (in particular re: consts
488-
// referring to statics).
489-
return Ok(());
479+
match self.ctfe_mode {
480+
Some(CtfeValidationMode::Static { .. }) => {
481+
// We skip recursively checking other statics. These statics must be sound by
482+
// themselves, and the only way to get broken statics here is by using
483+
// unsafe code.
484+
// The reasons we don't check other statics is twofold. For one, in all
485+
// sound cases, the static was already validated on its own, and second, we
486+
// trigger cycle errors if we try to compute the value of the other static
487+
// and that static refers back to us.
488+
// This could miss some UB, but that's fine.
489+
return Ok(());
490+
}
491+
Some(CtfeValidationMode::Const { .. }) => {
492+
// For consts on the other hand we have to recursively check;
493+
// pattern matching assumes a valid value. However we better make
494+
// sure this is not mutable.
495+
if is_mut {
496+
throw_validation_failure!(self.path, ConstRefToMutable);
497+
}
498+
}
499+
None => {}
500+
}
490501
}
491502
GlobalAlloc::Memory(alloc) => {
492503
if alloc.inner().mutability == Mutability::Mut
493504
&& matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. }))
494505
{
495-
// This is impossible: this can only be some inner allocation of a
496-
// `static mut` (everything else either hits the `GlobalAlloc::Static`
497-
// case or is interned immutably). To get such a pointer we'd have to
498-
// load it from a static, but such loads lead to a CTFE error.
499-
span_bug!(
500-
self.ecx.tcx.span,
501-
"encountered reference to mutable memory inside a `const`"
502-
);
506+
throw_validation_failure!(self.path, ConstRefToMutable);
503507
}
504508
if ptr_expected_mutbl == Mutability::Mut
505509
&& alloc.inner().mutability == Mutability::Not
@@ -979,7 +983,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
979983
Err(err) => {
980984
bug!(
981985
"Unexpected Undefined Behavior error during validation: {}",
982-
self.format_error(err)
986+
format_interp_error(self.tcx.dcx(), err)
983987
);
984988
}
985989
}

compiler/rustc_middle/src/mir/interpret/error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ pub enum ValidationErrorKind<'tcx> {
425425
PtrToUninhabited { ptr_kind: PointerKind, ty: Ty<'tcx> },
426426
PtrToStatic { ptr_kind: PointerKind },
427427
MutableRefInConst,
428+
ConstRefToMutable,
428429
MutableRefToImmutable,
429430
UnsafeCellInImmutable,
430431
NullFnPtr,

compiler/rustc_mir_transform/src/const_prop_lint.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use either::Left;
77

88
use rustc_const_eval::interpret::Immediate;
99
use rustc_const_eval::interpret::{
10-
InterpCx, InterpResult, MemoryKind, OpTy, Scalar, StackPopCleanup,
10+
format_interp_error, InterpCx, InterpResult, MemoryKind, OpTy, Scalar, StackPopCleanup,
1111
};
1212
use rustc_const_eval::ReportErrorExt;
1313
use rustc_hir::def::DefKind;
@@ -236,7 +236,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
236236
assert!(
237237
!error.kind().formatted_string(),
238238
"const-prop encountered formatting error: {}",
239-
self.ecx.format_error(error),
239+
format_interp_error(self.ecx.tcx.dcx(), error),
240240
);
241241
None
242242
}

src/tools/miri/src/diagnostics.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ pub fn report_error<'tcx, 'mir>(
290290
) =>
291291
{
292292
ecx.handle_ice(); // print interpreter backtrace
293-
bug!("This validation error should be impossible in Miri: {}", ecx.format_error(e));
293+
bug!("This validation error should be impossible in Miri: {}", format_interp_error(ecx.tcx.dcx(), e));
294294
}
295295
UndefinedBehavior(_) => "Undefined Behavior",
296296
ResourceExhaustion(_) => "resource exhaustion",
@@ -304,7 +304,7 @@ pub fn report_error<'tcx, 'mir>(
304304
) => "post-monomorphization error",
305305
_ => {
306306
ecx.handle_ice(); // print interpreter backtrace
307-
bug!("This error should be impossible in Miri: {}", ecx.format_error(e));
307+
bug!("This error should be impossible in Miri: {}", format_interp_error(ecx.tcx.dcx(), e));
308308
}
309309
};
310310
#[rustfmt::skip]
@@ -370,7 +370,7 @@ pub fn report_error<'tcx, 'mir>(
370370
_ => {}
371371
}
372372

373-
msg.insert(0, ecx.format_error(e));
373+
msg.insert(0, format_interp_error(ecx.tcx.dcx(), e));
374374

375375
report_msg(
376376
DiagLevel::Error,

0 commit comments

Comments
 (0)