Skip to content

Commit c6ec858

Browse files
committed
Forbid references to statics in valtrees
1 parent 5549ffd commit c6ec858

10 files changed

+91
-15
lines changed

compiler/rustc_const_eval/messages.ftl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,8 @@ const_eval_realloc_or_alloc_with_offset =
310310
311311
const_eval_recursive_static = encountered static that tried to initialize itself with itself
312312
313+
const_eval_ref_to_static = encountered a reference pointing to a static variable in a constant
314+
313315
const_eval_remainder_by_zero =
314316
calculating the remainder with a divisor of zero
315317
const_eval_remainder_overflow =
@@ -399,7 +401,6 @@ const_eval_unwind_past_top =
399401
400402
## The `front_matter`s here refer to either `const_eval_front_matter_invalid_value` or `const_eval_front_matter_invalid_value_with_path`.
401403
## (We'd love to sort this differently to make that more clear but tidy won't let us...)
402-
const_eval_validation_box_to_static = {$front_matter}: encountered a box pointing to a static variable in a constant
403404
const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty}
404405
405406
const_eval_validation_const_ref_to_extern = {$front_matter}: encountered reference to `extern` static in `const`

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ pub enum CheckAlignment {
8080

8181
#[derive(Copy, Clone, PartialEq)]
8282
pub(crate) enum GlobalAccessPermissions {
83+
/// Not allowed to read from static items at all
84+
Nothing,
8385
/// Allowed to read from immutable statics
8486
Static,
8587
/// Allowed to read from mutable statics
@@ -686,7 +688,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
686688
machine: &Self,
687689
alloc_id: AllocId,
688690
alloc: ConstAllocation<'tcx>,
689-
_static_def_id: Option<DefId>,
691+
static_def_id: Option<DefId>,
690692
is_write: bool,
691693
) -> InterpResult<'tcx> {
692694
let alloc = alloc.inner();
@@ -697,19 +699,26 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
697699
Mutability::Mut => Err(ConstEvalErrKind::ModifiedGlobal.into()),
698700
}
699701
} else {
700-
// Read access. These are usually allowed, with some exceptions.
702+
let check_mutability = || match alloc.mutability {
703+
Mutability::Mut => {
704+
// Machine configuration does not allow us to read statics (e.g., `const`
705+
// initializer).
706+
Err(ConstEvalErrKind::ConstAccessesMutGlobal.into())
707+
}
708+
// Immutable global, this read is fine.
709+
Mutability::Not => Ok(()),
710+
};
701711
match machine.global_access_permissions {
702712
// Machine configuration allows us read from anything (e.g., `static` initializer).
703713
GlobalAccessPermissions::StaticMut => Ok(()),
704-
GlobalAccessPermissions::Static => match alloc.mutability {
705-
Mutability::Mut => {
706-
// Machine configuration does not allow us to read statics (e.g., `const`
707-
// initializer).
714+
GlobalAccessPermissions::Static => check_mutability(),
715+
GlobalAccessPermissions::Nothing => {
716+
if static_def_id.is_none() {
717+
check_mutability()
718+
} else {
708719
Err(ConstEvalErrKind::ConstAccessesMutGlobal.into())
709720
}
710-
// Immutable global, this read is fine.
711-
Mutability::Not => Ok(()),
712-
},
721+
}
713722
}
714723
}
715724
}

compiler/rustc_const_eval/src/const_eval/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ pub(crate) enum ValTreeCreationError {
3131
NodesOverflow,
3232
/// Values of this type, or this particular value, are not supported as valtrees.
3333
NonSupportedType,
34+
/// Tried to create a valtree with a reference to a static.
35+
StaticRef,
3436
}
3537
pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError>;
3638

compiler/rustc_const_eval/src/const_eval/valtrees.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use super::machine::CompileTimeInterpCx;
1313
use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES};
1414
use crate::const_eval::GlobalAccessPermissions;
1515
use crate::errors::MaxNumNodesInConstErr;
16+
use crate::errors::StaticRefErr;
1617
use crate::interpret::MPlaceTy;
1718
use crate::interpret::{
1819
intern_const_alloc_recursive, ImmTy, Immediate, InternKind, MemPlaceMeta, MemoryKind, PlaceTy,
@@ -138,6 +139,16 @@ fn const_to_valtree_inner<'tcx>(
138139

139140
ty::Ref(_, _, _) => {
140141
let derefd_place = ecx.deref_pointer(place)?;
142+
if let Some(prov) = derefd_place.ptr().provenance {
143+
match ecx.tcx.global_alloc(prov.alloc_id()) {
144+
mir::interpret::GlobalAlloc::Function(_) => unreachable!(),
145+
mir::interpret::GlobalAlloc::VTable(_, _) => unreachable!(),
146+
mir::interpret::GlobalAlloc::Static(_) => {
147+
return Err(ValTreeCreationError::StaticRef);
148+
},
149+
mir::interpret::GlobalAlloc::Memory(_) => {},
150+
}
151+
}
141152
const_to_valtree_inner(ecx, &derefd_place, num_nodes)
142153
}
143154

@@ -236,7 +247,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
236247
let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?;
237248

238249
// FIXME Need to provide a span to `eval_to_valtree`
239-
let ecx = mk_eval_cx_to_read_const_val(
250+
let mut ecx = mk_eval_cx_to_read_const_val(
240251
tcx,
241252
DUMMY_SP,
242253
param_env,
@@ -248,6 +259,14 @@ pub(crate) fn eval_to_valtree<'tcx>(
248259
debug!(?place);
249260

250261
let mut num_nodes = 0;
262+
263+
// To preserve provenance of static items, it is crucial that we do not
264+
// treat them as constants and just read their values.
265+
// This flag will cause valtree creation to ICE if a reference to a static
266+
// is read, so valtree creation needs to eagerly catch those cases and handle
267+
// them in custom ways. Currently by reporting a hard error, but we can opt to
268+
// create a special valtree node for statics in the future.
269+
ecx.machine.global_access_permissions = GlobalAccessPermissions::Nothing;
251270
let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes);
252271

253272
match valtree_result {
@@ -262,6 +281,10 @@ pub(crate) fn eval_to_valtree<'tcx>(
262281
tcx.dcx().emit_err(MaxNumNodesInConstErr { span, global_const_id });
263282
Err(handled.into())
264283
}
284+
ValTreeCreationError::StaticRef => {
285+
let handled = tcx.dcx().emit_err(StaticRefErr { span });
286+
Err(handled.into())
287+
}
265288
ValTreeCreationError::NonSupportedType => Ok(None),
266289
}
267290
}

compiler/rustc_const_eval/src/errors.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,13 @@ pub(crate) struct MaxNumNodesInConstErr {
126126
pub global_const_id: String,
127127
}
128128

129+
#[derive(Diagnostic)]
130+
#[diag(const_eval_ref_to_static)]
131+
pub(crate) struct StaticRefErr {
132+
#[primary_span]
133+
pub span: Option<Span>,
134+
}
135+
129136
#[derive(Diagnostic)]
130137
#[diag(const_eval_unallowed_fn_pointer_call)]
131138
pub(crate) struct UnallowedFnPointerCall {

tests/ui/consts/const_refs_to_static.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,4 @@ const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) };
1414
fn main() {
1515
assert_eq!(*C1, 0);
1616
assert_eq!(unsafe { *C2 }, 0);
17-
// Computing this pattern will read from an immutable static. That's fine.
18-
assert!(matches!(&0, C1));
1917
}

tests/ui/consts/const_refs_to_static_fail_invalid.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,20 @@ fn mutable() {
4848
}
4949
}
5050

51+
fn immutable() {
52+
static S: i32 = 0;
53+
54+
const C: &i32 = unsafe { &S };
55+
//~^ ERROR: encountered a reference pointing to a static variable in a constant
56+
57+
// This could be ok, but we'd need to teach valtrees to support
58+
// preserving statics, because valtree creation is shared with
59+
// const generics, which can't just erase the information about
60+
// the static's address.
61+
match &42 {
62+
C => {} //~ERROR: could not evaluate constant pattern
63+
_ => {}
64+
}
65+
}
66+
5167
fn main() {}

tests/ui/consts/const_refs_to_static_fail_invalid.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,18 @@ error: could not evaluate constant pattern
4949
LL | C => {}
5050
| ^
5151

52-
error: aborting due to 6 previous errors
52+
error: encountered a reference pointing to a static variable in a constant
53+
--> $DIR/const_refs_to_static_fail_invalid.rs:54:5
54+
|
55+
LL | const C: &i32 = unsafe { &S };
56+
| ^^^^^^^^^^^^^
57+
58+
error: could not evaluate constant pattern
59+
--> $DIR/const_refs_to_static_fail_invalid.rs:62:9
60+
|
61+
LL | C => {}
62+
| ^
63+
64+
error: aborting due to 8 previous errors
5365

5466
For more information about this error, try `rustc --explain E0080`.

tests/ui/statics/const_generics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! check that we lose the information that `BAR` points to `FOO`
22
//! when going through a const generic.
33
4-
//@ run-pass
54
// With optimizations, LLVM will deduplicate the constant `X` whose
65
// value is `&42` to just be a reference to the static. This is correct,
76
// but obscures the issue we're trying to show.
@@ -19,4 +18,5 @@ fn foo<const X: &'static usize>() {
1918

2019
fn main() {
2120
foo::<BAR>();
21+
//~^ ERROR: encountered a reference pointing to a static variable in a constant
2222
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: encountered a reference pointing to a static variable in a constant
2+
--> $DIR/const_generics.rs:20:11
3+
|
4+
LL | foo::<BAR>();
5+
| ^^^
6+
7+
error: aborting due to 1 previous error
8+

0 commit comments

Comments
 (0)