Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 22106c3

Browse files
committedOct 15, 2023
const validation: ensure we don't have &mut to read-only memory or UnsafeCell in read-only memory
1 parent 3fd5624 commit 22106c3

13 files changed

+405
-66
lines changed
 

‎compiler/rustc_const_eval/messages.ftl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ const_eval_validation_invalid_fn_ptr = {$front_matter}: encountered {$value}, bu
438438
const_eval_validation_invalid_ref_meta = {$front_matter}: encountered invalid reference metadata: total size is bigger than largest supported object
439439
const_eval_validation_invalid_ref_slice_meta = {$front_matter}: encountered invalid reference metadata: slice is bigger than largest supported object
440440
const_eval_validation_invalid_vtable_ptr = {$front_matter}: encountered {$value}, but expected a vtable pointer
441-
const_eval_validation_mutable_ref_in_const = {$front_matter}: encountered mutable reference in a `const`
441+
const_eval_validation_mutable_ref_to_immutable = {$front_matter}: encountered mutable reference or box pointing to read-only memory
442442
const_eval_validation_never_val = {$front_matter}: encountered a value of the never type `!`
443443
const_eval_validation_null_box = {$front_matter}: encountered a null box
444444
const_eval_validation_null_fn_ptr = {$front_matter}: encountered a null function pointer
@@ -456,7 +456,7 @@ const_eval_validation_unaligned_ref = {$front_matter}: encountered an unaligned
456456
const_eval_validation_uninhabited_enum_variant = {$front_matter}: encountered an uninhabited enum variant
457457
const_eval_validation_uninhabited_val = {$front_matter}: encountered a value of uninhabited type `{$ty}`
458458
const_eval_validation_uninit = {$front_matter}: encountered uninitialized memory, but {$expected}
459-
const_eval_validation_unsafe_cell = {$front_matter}: encountered `UnsafeCell` in a `const`
459+
const_eval_validation_unsafe_cell = {$front_matter}: encountered `UnsafeCell` in read-only memory
460460
461461
const_eval_write_to_read_only =
462462
writing to {$allocation} which is read-only

‎compiler/rustc_const_eval/src/const_eval/eval_queries.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,10 +336,21 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
336336
let mode = match tcx.static_mutability(cid.instance.def_id()) {
337337
Some(_) if cid.promoted.is_some() => {
338338
// Promoteds in statics are allowed to point to statics.
339-
CtfeValidationMode::Const { inner, allow_static_ptrs: true }
339+
CtfeValidationMode::Const {
340+
allow_immutable_unsafe_cell: false,
341+
allow_static_ptrs: true,
342+
}
340343
}
341344
Some(_) => CtfeValidationMode::Regular, // a `static`
342-
None => CtfeValidationMode::Const { inner, allow_static_ptrs: false },
345+
None => {
346+
// In normal `const` (not promoted), the outermost allocation is always only copied,
347+
// so having `UnsafeCell` in there is okay despite them being in immutable memory.
348+
let allow_immutable_unsafe_cell = cid.promoted.is_none() && !inner;
349+
CtfeValidationMode::Const {
350+
allow_immutable_unsafe_cell,
351+
allow_static_ptrs: false,
352+
}
353+
}
343354
};
344355
ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
345356
inner = true;

‎compiler/rustc_const_eval/src/errors.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -625,13 +625,13 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
625625

626626
PointerAsInt { .. } => const_eval_validation_pointer_as_int,
627627
PartialPointer => const_eval_validation_partial_pointer,
628-
MutableRefInConst => const_eval_validation_mutable_ref_in_const,
628+
MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
629629
NullFnPtr => const_eval_validation_null_fn_ptr,
630630
NeverVal => const_eval_validation_never_val,
631631
NullablePtrOutOfRange { .. } => const_eval_validation_nullable_ptr_out_of_range,
632632
PtrOutOfRange { .. } => const_eval_validation_ptr_out_of_range,
633633
OutOfRange { .. } => const_eval_validation_out_of_range,
634-
UnsafeCell => const_eval_validation_unsafe_cell,
634+
UnsafeCellInImmutable => const_eval_validation_unsafe_cell,
635635
UninhabitedVal { .. } => const_eval_validation_uninhabited_val,
636636
InvalidEnumTag { .. } => const_eval_validation_invalid_enum_tag,
637637
UninhabitedEnumVariant => const_eval_validation_uninhabited_enum_variant,
@@ -778,10 +778,10 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
778778
NullPtr { .. }
779779
| PtrToStatic { .. }
780780
| PtrToMut { .. }
781-
| MutableRefInConst
781+
| MutableRefToImmutable
782782
| NullFnPtr
783783
| NeverVal
784-
| UnsafeCell
784+
| UnsafeCellInImmutable
785785
| InvalidMetaSliceTooLarge { .. }
786786
| InvalidMetaTooLarge { .. }
787787
| DanglingPtrUseAfterFree { .. }

‎compiler/rustc_const_eval/src/interpret/validity.rs

Lines changed: 94 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ use std::num::NonZeroUsize;
99

1010
use either::{Left, Right};
1111

12+
use hir::def::DefKind;
1213
use rustc_ast::Mutability;
1314
use rustc_data_structures::fx::FxHashSet;
1415
use rustc_hir as hir;
1516
use rustc_middle::mir::interpret::{
16-
ExpectedKind, InterpError, InvalidMetaKind, PointerKind, ValidationErrorInfo,
17+
ExpectedKind, InterpError, InvalidMetaKind, PointerKind, Provenance, ValidationErrorInfo,
1718
ValidationErrorKind, ValidationErrorKind::*,
1819
};
1920
use rustc_middle::ty;
@@ -123,15 +124,34 @@ pub enum PathElem {
123124
}
124125

125126
/// Extra things to check for during validation of CTFE results.
127+
#[derive(Copy, Clone)]
126128
pub enum CtfeValidationMode {
127129
/// Regular validation, nothing special happening.
128130
Regular,
129131
/// Validation of a `const`.
130-
/// `inner` says if this is an inner, indirect allocation (as opposed to the top-level const
131-
/// allocation). Being an inner allocation makes a difference because the top-level allocation
132-
/// of a `const` is copied for each use, but the inner allocations are implicitly shared.
132+
/// `allow_immutable_unsafe_cell` says whether we allow `UnsafeCell` in immutable memory (which is the
133+
/// case for the top-level allocation of a `const`, where this is fine because the allocation will be
134+
/// copied at each use site).
133135
/// `allow_static_ptrs` says if pointers to statics are permitted (which is the case for promoteds in statics).
134-
Const { inner: bool, allow_static_ptrs: bool },
136+
Const { allow_immutable_unsafe_cell: bool, allow_static_ptrs: bool },
137+
}
138+
139+
impl CtfeValidationMode {
140+
fn allow_immutable_unsafe_cell(self) -> bool {
141+
match self {
142+
CtfeValidationMode::Regular => false,
143+
CtfeValidationMode::Const { allow_immutable_unsafe_cell, .. } => {
144+
allow_immutable_unsafe_cell
145+
}
146+
}
147+
}
148+
149+
fn allow_static_ptrs(self) -> bool {
150+
match self {
151+
CtfeValidationMode::Regular => true, // statics can point to statics
152+
CtfeValidationMode::Const { allow_static_ptrs, .. } => allow_static_ptrs,
153+
}
154+
}
135155
}
136156

137157
/// State for tracking recursive validation of references
@@ -412,6 +432,21 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
412432
}
413433
// Recursive checking
414434
if let Some(ref_tracking) = self.ref_tracking.as_deref_mut() {
435+
// Determine whether this pointer expects to be pointing to something mutable.
436+
let ptr_expected_mutbl = match ptr_kind {
437+
PointerKind::Box => Mutability::Mut,
438+
PointerKind::Ref => {
439+
let tam = value.layout.ty.builtin_deref(false).unwrap();
440+
// ZST never require mutability. We do not take into account interior mutability here
441+
// since we cannot know if there really is an `UnsafeCell` -- so we check that
442+
// in the recursive descent behind this reference.
443+
if size == Size::ZERO || tam.mutbl == Mutability::Not {
444+
Mutability::Not
445+
} else {
446+
Mutability::Mut
447+
}
448+
}
449+
};
415450
// Proceed recursively even for ZST, no reason to skip them!
416451
// `!` is a ZST and we want to validate it.
417452
if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr()) {
@@ -422,16 +457,29 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
422457
// Special handling for pointers to statics (irrespective of their type).
423458
assert!(!self.ecx.tcx.is_thread_local_static(did));
424459
assert!(self.ecx.tcx.is_static(did));
425-
if matches!(
426-
self.ctfe_mode,
427-
Some(CtfeValidationMode::Const { allow_static_ptrs: false, .. })
428-
) {
460+
if self.ctfe_mode.is_some_and(|c| !c.allow_static_ptrs()) {
429461
// See const_eval::machine::MemoryExtra::can_access_statics for why
430462
// this check is so important.
431463
// This check is reachable when the const just referenced the static,
432464
// but never read it (so we never entered `before_access_global`).
433465
throw_validation_failure!(self.path, PtrToStatic { ptr_kind });
434466
}
467+
// Mutability check.
468+
if ptr_expected_mutbl == Mutability::Mut {
469+
if matches!(
470+
self.ecx.tcx.def_kind(did),
471+
DefKind::Static(Mutability::Not)
472+
) && self
473+
.ecx
474+
.tcx
475+
.type_of(did)
476+
.no_bound_vars()
477+
.expect("statics should not have generic parameters")
478+
.is_freeze(*self.ecx.tcx, ty::ParamEnv::reveal_all())
479+
{
480+
throw_validation_failure!(self.path, MutableRefToImmutable);
481+
}
482+
}
435483
// We skip recursively checking other statics. These statics must be sound by
436484
// themselves, and the only way to get broken statics here is by using
437485
// unsafe code.
@@ -453,9 +501,20 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
453501
// and we would catch that here.
454502
throw_validation_failure!(self.path, PtrToMut { ptr_kind });
455503
}
504+
if ptr_expected_mutbl == Mutability::Mut
505+
&& alloc.inner().mutability == Mutability::Not
506+
{
507+
throw_validation_failure!(self.path, MutableRefToImmutable);
508+
}
456509
}
457-
// Nothing to check for these.
458-
None | Some(GlobalAlloc::Function(..) | GlobalAlloc::VTable(..)) => {}
510+
Some(GlobalAlloc::Function(..) | GlobalAlloc::VTable(..)) => {
511+
// These are immutable, we better don't allow mutable pointers here.
512+
if ptr_expected_mutbl == Mutability::Mut {
513+
throw_validation_failure!(self.path, MutableRefToImmutable);
514+
}
515+
}
516+
// Dangling, already handled.
517+
None => bug!(),
459518
}
460519
}
461520
let path = &self.path;
@@ -525,17 +584,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
525584
}
526585
Ok(true)
527586
}
528-
ty::Ref(_, ty, mutbl) => {
529-
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. }))
530-
&& *mutbl == Mutability::Mut
531-
{
532-
// A mutable reference inside a const? That does not seem right (except if it is
533-
// a ZST).
534-
let layout = self.ecx.layout_of(*ty)?;
535-
if !layout.is_zst() {
536-
throw_validation_failure!(self.path, MutableRefInConst);
537-
}
538-
}
587+
ty::Ref(..) => {
539588
self.check_safe_pointer(value, PointerKind::Ref)?;
540589
Ok(true)
541590
}
@@ -636,6 +685,19 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
636685
)
637686
}
638687
}
688+
689+
fn in_mutable_memory(&self, op: &OpTy<'tcx, M::Provenance>) -> bool {
690+
if let Some(mplace) = op.as_mplace_or_imm().left() {
691+
if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) {
692+
if self.ecx.tcx.global_alloc(alloc_id).unwrap_memory().inner().mutability
693+
== Mutability::Mut
694+
{
695+
return true;
696+
}
697+
}
698+
}
699+
false
700+
}
639701
}
640702

641703
impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
@@ -699,10 +761,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
699761
op: &OpTy<'tcx, M::Provenance>,
700762
_fields: NonZeroUsize,
701763
) -> InterpResult<'tcx> {
702-
// Special check preventing `UnsafeCell` inside unions in the inner part of constants.
703-
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) {
764+
// Special check for CTFE validation, preventing `UnsafeCell` inside unions in immutable memory.
765+
if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) {
704766
if !op.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.param_env) {
705-
throw_validation_failure!(self.path, UnsafeCell);
767+
if !self.in_mutable_memory(op) {
768+
throw_validation_failure!(self.path, UnsafeCellInImmutable);
769+
}
706770
}
707771
}
708772
Ok(())
@@ -724,11 +788,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
724788
}
725789

726790
// Special check preventing `UnsafeCell` in the inner part of constants
727-
if let Some(def) = op.layout.ty.ty_adt_def() {
728-
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. }))
729-
&& def.is_unsafe_cell()
730-
{
731-
throw_validation_failure!(self.path, UnsafeCell);
791+
if self.ctfe_mode.is_some_and(|c| !c.allow_immutable_unsafe_cell()) {
792+
if let Some(def) = op.layout.ty.ty_adt_def() && def.is_unsafe_cell() {
793+
if !self.in_mutable_memory(op) {
794+
throw_validation_failure!(self.path, UnsafeCellInImmutable);
795+
}
732796
}
733797
}
734798

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,13 +414,13 @@ pub enum ValidationErrorKind<'tcx> {
414414
PtrToUninhabited { ptr_kind: PointerKind, ty: Ty<'tcx> },
415415
PtrToStatic { ptr_kind: PointerKind },
416416
PtrToMut { ptr_kind: PointerKind },
417-
MutableRefInConst,
417+
MutableRefToImmutable,
418+
UnsafeCellInImmutable,
418419
NullFnPtr,
419420
NeverVal,
420421
NullablePtrOutOfRange { range: WrappingRange, max_value: u128 },
421422
PtrOutOfRange { range: WrappingRange, max_value: u128 },
422423
OutOfRange { value: String, range: WrappingRange, max_value: u128 },
423-
UnsafeCell,
424424
UninhabitedVal { ty: Ty<'tcx> },
425425
InvalidEnumTag { value: String },
426426
UninhabitedEnumVariant,

‎tests/ui/consts/invalid-union.32bit.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
22
--> $DIR/invalid-union.rs:41:1
33
|
44
LL | fn main() {
5-
| ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const`
5+
| ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in read-only memory
66
|
77
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
88
= note: the raw bytes of the constant (size: 4, align: 4) {

‎tests/ui/consts/invalid-union.64bit.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
22
--> $DIR/invalid-union.rs:41:1
33
|
44
LL | fn main() {
5-
| ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const`
5+
| ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in read-only memory
66
|
77
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
88
= note: the raw bytes of the constant (size: 8, align: 8) {

‎tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,79 @@ error[E0080]: it is undefined behavior to use this value
22
--> $DIR/mutable_references_err.rs:15:1
33
|
44
LL | const MUH: Meh = Meh {
5-
| ^^^^^^^^^^^^^^ constructing invalid value at .x.<deref>: encountered `UnsafeCell` in a `const`
5+
| ^^^^^^^^^^^^^^ constructing invalid value at .x.<deref>: encountered `UnsafeCell` in read-only memory
66
|
77
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
88
= note: the raw bytes of the constant (size: 4, align: 4) {
9-
╾─alloc3──╼ │ ╾──╼
9+
╾─alloc4──╼ │ ╾──╼
1010
}
1111

1212
error[E0080]: it is undefined behavior to use this value
13-
--> $DIR/mutable_references_err.rs:25:1
13+
--> $DIR/mutable_references_err.rs:26:1
1414
|
1515
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
16-
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in a `const`
16+
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in read-only memory
1717
|
1818
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
1919
= note: the raw bytes of the constant (size: 8, align: 4) {
20-
╾─alloc7──╼ ╾─alloc8──╼ │ ╾──╼╾──╼
20+
╾─alloc8──╼ ╾─alloc9──╼ │ ╾──╼╾──╼
2121
}
2222

2323
error[E0080]: it is undefined behavior to use this value
24-
--> $DIR/mutable_references_err.rs:29:1
24+
--> $DIR/mutable_references_err.rs:32:1
25+
|
26+
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
27+
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant
28+
|
29+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
30+
= note: the raw bytes of the constant (size: 4, align: 4) {
31+
╾─alloc1──╼ │ ╾──╼
32+
}
33+
34+
error[E0080]: it is undefined behavior to use this value
35+
--> $DIR/mutable_references_err.rs:35:1
2536
|
2637
LL | const BLUNT: &mut i32 = &mut 42;
27-
| ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const`
38+
| ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory
2839
|
2940
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
3041
= note: the raw bytes of the constant (size: 4, align: 4) {
31-
╾─alloc10─╼ │ ╾──╼
42+
╾─alloc13─╼ │ ╾──╼
3243
}
3344

3445
warning: skipping const checks
3546
|
3647
help: skipping check that does not even have a feature gate
37-
--> $DIR/mutable_references_err.rs:16:8
48+
--> $DIR/mutable_references_err.rs:17:8
3849
|
3950
LL | x: &UnsafeCell::new(42),
4051
| ^^^^^^^^^^^^^^^^^^^^
4152
help: skipping check that does not even have a feature gate
42-
--> $DIR/mutable_references_err.rs:25:27
53+
--> $DIR/mutable_references_err.rs:26:27
4354
|
4455
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
4556
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4657
help: skipping check that does not even have a feature gate
47-
--> $DIR/mutable_references_err.rs:29:25
58+
--> $DIR/mutable_references_err.rs:32:40
59+
|
60+
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
61+
| ^^^
62+
help: skipping check that does not even have a feature gate
63+
--> $DIR/mutable_references_err.rs:32:40
64+
|
65+
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
66+
| ^^^
67+
help: skipping check that does not even have a feature gate
68+
--> $DIR/mutable_references_err.rs:32:35
69+
|
70+
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
71+
| ^^^^^^^^
72+
help: skipping check that does not even have a feature gate
73+
--> $DIR/mutable_references_err.rs:35:25
4874
|
4975
LL | const BLUNT: &mut i32 = &mut 42;
5076
| ^^^^^^^
5177

52-
error: aborting due to 3 previous errors; 1 warning emitted
78+
error: aborting due to 4 previous errors; 1 warning emitted
5379

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

‎tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,79 @@ error[E0080]: it is undefined behavior to use this value
22
--> $DIR/mutable_references_err.rs:15:1
33
|
44
LL | const MUH: Meh = Meh {
5-
| ^^^^^^^^^^^^^^ constructing invalid value at .x.<deref>: encountered `UnsafeCell` in a `const`
5+
| ^^^^^^^^^^^^^^ constructing invalid value at .x.<deref>: encountered `UnsafeCell` in read-only memory
66
|
77
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
88
= note: the raw bytes of the constant (size: 8, align: 8) {
9-
╾───────alloc3────────╼ │ ╾──────╼
9+
╾───────alloc4────────╼ │ ╾──────╼
1010
}
1111

1212
error[E0080]: it is undefined behavior to use this value
13-
--> $DIR/mutable_references_err.rs:25:1
13+
--> $DIR/mutable_references_err.rs:26:1
1414
|
1515
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
16-
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in a `const`
16+
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in read-only memory
1717
|
1818
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
1919
= note: the raw bytes of the constant (size: 16, align: 8) {
20-
╾───────alloc7────────╼ ╾───────alloc8────────╼ │ ╾──────╼╾──────╼
20+
╾───────alloc8────────╼ ╾───────alloc9────────╼ │ ╾──────╼╾──────╼
2121
}
2222

2323
error[E0080]: it is undefined behavior to use this value
24-
--> $DIR/mutable_references_err.rs:29:1
24+
--> $DIR/mutable_references_err.rs:32:1
25+
|
26+
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
27+
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant
28+
|
29+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
30+
= note: the raw bytes of the constant (size: 8, align: 8) {
31+
╾───────alloc1────────╼ │ ╾──────╼
32+
}
33+
34+
error[E0080]: it is undefined behavior to use this value
35+
--> $DIR/mutable_references_err.rs:35:1
2536
|
2637
LL | const BLUNT: &mut i32 = &mut 42;
27-
| ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference in a `const`
38+
| ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory
2839
|
2940
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
3041
= note: the raw bytes of the constant (size: 8, align: 8) {
31-
╾───────alloc10───────╼ │ ╾──────╼
42+
╾───────alloc13───────╼ │ ╾──────╼
3243
}
3344

3445
warning: skipping const checks
3546
|
3647
help: skipping check that does not even have a feature gate
37-
--> $DIR/mutable_references_err.rs:16:8
48+
--> $DIR/mutable_references_err.rs:17:8
3849
|
3950
LL | x: &UnsafeCell::new(42),
4051
| ^^^^^^^^^^^^^^^^^^^^
4152
help: skipping check that does not even have a feature gate
42-
--> $DIR/mutable_references_err.rs:25:27
53+
--> $DIR/mutable_references_err.rs:26:27
4354
|
4455
LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
4556
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4657
help: skipping check that does not even have a feature gate
47-
--> $DIR/mutable_references_err.rs:29:25
58+
--> $DIR/mutable_references_err.rs:32:40
59+
|
60+
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
61+
| ^^^
62+
help: skipping check that does not even have a feature gate
63+
--> $DIR/mutable_references_err.rs:32:40
64+
|
65+
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
66+
| ^^^
67+
help: skipping check that does not even have a feature gate
68+
--> $DIR/mutable_references_err.rs:32:35
69+
|
70+
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
71+
| ^^^^^^^^
72+
help: skipping check that does not even have a feature gate
73+
--> $DIR/mutable_references_err.rs:35:25
4874
|
4975
LL | const BLUNT: &mut i32 = &mut 42;
5076
| ^^^^^^^
5177

52-
error: aborting due to 3 previous errors; 1 warning emitted
78+
error: aborting due to 4 previous errors; 1 warning emitted
5379

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

‎tests/ui/consts/miri_unleashed/mutable_references_err.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ unsafe impl Sync for Meh {}
1313
// the following will never be ok! no interior mut behind consts, because
1414
// all allocs interned here will be marked immutable.
1515
const MUH: Meh = Meh { //~ ERROR: it is undefined behavior to use this value
16+
//~| UnsafeCell
1617
x: &UnsafeCell::new(42),
1718
};
1819

@@ -24,10 +25,16 @@ unsafe impl Sync for Synced {}
2425
// Make sure we also catch this behind a type-erased `dyn Trait` reference.
2526
const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
2627
//~^ ERROR: it is undefined behavior to use this value
28+
//~| UnsafeCell
2729

2830
// Make sure we also catch mutable references.
31+
static mut FOO: i32 = 0;
32+
const SUBTLE: &mut i32 = unsafe { &mut FOO };
33+
//~^ ERROR: it is undefined behavior to use this value
34+
//~| static
2935
const BLUNT: &mut i32 = &mut 42;
3036
//~^ ERROR: it is undefined behavior to use this value
37+
//~| mutable reference
3138

3239
fn main() {
3340
unsafe {
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
error[E0080]: it is undefined behavior to use this value
2+
--> $DIR/static-no-inner-interior-mut.rs:9:1
3+
|
4+
LL | static REF: &AtomicI32 = &AtomicI32::new(42);
5+
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.v: encountered `UnsafeCell` in read-only memory
6+
|
7+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
8+
= note: the raw bytes of the constant (size: 4, align: 4) {
9+
╾─alloc4──╼ │ ╾──╼
10+
}
11+
12+
error[E0080]: it is undefined behavior to use this value
13+
--> $DIR/static-no-inner-interior-mut.rs:11:1
14+
|
15+
LL | static REFMUT: &mut i32 = &mut 0;
16+
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory
17+
|
18+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
19+
= note: the raw bytes of the constant (size: 4, align: 4) {
20+
╾─alloc6──╼ │ ╾──╼
21+
}
22+
23+
error[E0080]: it is undefined behavior to use this value
24+
--> $DIR/static-no-inner-interior-mut.rs:15:1
25+
|
26+
LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}};
27+
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.v: encountered `UnsafeCell` in read-only memory
28+
|
29+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
30+
= note: the raw bytes of the constant (size: 4, align: 4) {
31+
╾─alloc11─╼ │ ╾──╼
32+
}
33+
34+
error[E0080]: it is undefined behavior to use this value
35+
--> $DIR/static-no-inner-interior-mut.rs:17:1
36+
|
37+
LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}};
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory
39+
|
40+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
41+
= note: the raw bytes of the constant (size: 4, align: 4) {
42+
╾─alloc13─╼ │ ╾──╼
43+
}
44+
45+
error: encountered dangling pointer in final constant
46+
--> $DIR/static-no-inner-interior-mut.rs:28:1
47+
|
48+
LL | static RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr(&AtomicI32::new(42));
49+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
50+
51+
error: encountered dangling pointer in final constant
52+
--> $DIR/static-no-inner-interior-mut.rs:29:1
53+
|
54+
LL | static RAW_MUT: SyncPtr<i32> = SyncPtr(&mut 42 as *mut _ as *const _);
55+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
56+
57+
warning: skipping const checks
58+
|
59+
help: skipping check that does not even have a feature gate
60+
--> $DIR/static-no-inner-interior-mut.rs:9:26
61+
|
62+
LL | static REF: &AtomicI32 = &AtomicI32::new(42);
63+
| ^^^^^^^^^^^^^^^^^^^
64+
help: skipping check that does not even have a feature gate
65+
--> $DIR/static-no-inner-interior-mut.rs:11:27
66+
|
67+
LL | static REFMUT: &mut i32 = &mut 0;
68+
| ^^^^^^
69+
help: skipping check that does not even have a feature gate
70+
--> $DIR/static-no-inner-interior-mut.rs:15:56
71+
|
72+
LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}};
73+
| ^^^^
74+
help: skipping check that does not even have a feature gate
75+
--> $DIR/static-no-inner-interior-mut.rs:17:44
76+
|
77+
LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}};
78+
| ^^^^^^^^
79+
help: skipping check for `const_mut_refs` feature
80+
--> $DIR/static-no-inner-interior-mut.rs:29:40
81+
|
82+
LL | static RAW_MUT: SyncPtr<i32> = SyncPtr(&mut 42 as *mut _ as *const _);
83+
| ^^^^^^^
84+
85+
error: aborting due to 6 previous errors; 1 warning emitted
86+
87+
For more information about this error, try `rustc --explain E0080`.
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
error[E0080]: it is undefined behavior to use this value
2+
--> $DIR/static-no-inner-interior-mut.rs:9:1
3+
|
4+
LL | static REF: &AtomicI32 = &AtomicI32::new(42);
5+
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.v: encountered `UnsafeCell` in read-only memory
6+
|
7+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
8+
= note: the raw bytes of the constant (size: 8, align: 8) {
9+
╾───────alloc4────────╼ │ ╾──────╼
10+
}
11+
12+
error[E0080]: it is undefined behavior to use this value
13+
--> $DIR/static-no-inner-interior-mut.rs:11:1
14+
|
15+
LL | static REFMUT: &mut i32 = &mut 0;
16+
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory
17+
|
18+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
19+
= note: the raw bytes of the constant (size: 8, align: 8) {
20+
╾───────alloc6────────╼ │ ╾──────╼
21+
}
22+
23+
error[E0080]: it is undefined behavior to use this value
24+
--> $DIR/static-no-inner-interior-mut.rs:15:1
25+
|
26+
LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}};
27+
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.v: encountered `UnsafeCell` in read-only memory
28+
|
29+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
30+
= note: the raw bytes of the constant (size: 8, align: 8) {
31+
╾───────alloc11───────╼ │ ╾──────╼
32+
}
33+
34+
error[E0080]: it is undefined behavior to use this value
35+
--> $DIR/static-no-inner-interior-mut.rs:17:1
36+
|
37+
LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}};
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered mutable reference or box pointing to read-only memory
39+
|
40+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
41+
= note: the raw bytes of the constant (size: 8, align: 8) {
42+
╾───────alloc13───────╼ │ ╾──────╼
43+
}
44+
45+
error: encountered dangling pointer in final constant
46+
--> $DIR/static-no-inner-interior-mut.rs:28:1
47+
|
48+
LL | static RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr(&AtomicI32::new(42));
49+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
50+
51+
error: encountered dangling pointer in final constant
52+
--> $DIR/static-no-inner-interior-mut.rs:29:1
53+
|
54+
LL | static RAW_MUT: SyncPtr<i32> = SyncPtr(&mut 42 as *mut _ as *const _);
55+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
56+
57+
warning: skipping const checks
58+
|
59+
help: skipping check that does not even have a feature gate
60+
--> $DIR/static-no-inner-interior-mut.rs:9:26
61+
|
62+
LL | static REF: &AtomicI32 = &AtomicI32::new(42);
63+
| ^^^^^^^^^^^^^^^^^^^
64+
help: skipping check that does not even have a feature gate
65+
--> $DIR/static-no-inner-interior-mut.rs:11:27
66+
|
67+
LL | static REFMUT: &mut i32 = &mut 0;
68+
| ^^^^^^
69+
help: skipping check that does not even have a feature gate
70+
--> $DIR/static-no-inner-interior-mut.rs:15:56
71+
|
72+
LL | static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}};
73+
| ^^^^
74+
help: skipping check that does not even have a feature gate
75+
--> $DIR/static-no-inner-interior-mut.rs:17:44
76+
|
77+
LL | static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}};
78+
| ^^^^^^^^
79+
help: skipping check for `const_mut_refs` feature
80+
--> $DIR/static-no-inner-interior-mut.rs:29:40
81+
|
82+
LL | static RAW_MUT: SyncPtr<i32> = SyncPtr(&mut 42 as *mut _ as *const _);
83+
| ^^^^^^^
84+
85+
error: aborting due to 6 previous errors; 1 warning emitted
86+
87+
For more information about this error, try `rustc --explain E0080`.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// stderr-per-bitwidth
2+
// compile-flags: -Zunleash-the-miri-inside-of-you
3+
#![feature(const_refs_to_cell)]
4+
// All "inner" allocations that come with a `static` are interned immutably. This means it is
5+
// crucial that we do not accept any form of (interior) mutability there.
6+
7+
use std::sync::atomic::*;
8+
9+
static REF: &AtomicI32 = &AtomicI32::new(42); //~ERROR undefined behavior
10+
//~^ `UnsafeCell` in read-only memory
11+
static REFMUT: &mut i32 = &mut 0; //~ERROR undefined behavior
12+
//~^ pointing to read-only memory
13+
14+
// Different way of writing this that avoids promotion.
15+
static REF2: &AtomicI32 = {let x = AtomicI32::new(42); &{x}}; //~ERROR undefined behavior
16+
//~^ `UnsafeCell` in read-only memory
17+
static REFMUT2: &mut i32 = {let mut x = 0; &mut {x}}; //~ERROR undefined behavior
18+
//~^ pointing to read-only memory
19+
20+
// This one is obvious, since it is non-Sync. (It also suppresses the other errors, so it is
21+
// commented out.)
22+
// static RAW: *const AtomicI32 = &AtomicI32::new(42);
23+
24+
struct SyncPtr<T>(*const T);
25+
unsafe impl<T> Sync for SyncPtr<T> {}
26+
27+
// This one does not get promoted, and then the reference is simply too short-lived.
28+
static RAW_SYNC: SyncPtr<AtomicI32> = SyncPtr(&AtomicI32::new(42)); //~ERROR dangling pointer
29+
static RAW_MUT: SyncPtr<i32> = SyncPtr(&mut 42 as *mut _ as *const _); //~ERROR dangling pointer
30+
31+
fn main() {}

0 commit comments

Comments
 (0)
Please sign in to comment.