Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of rust-lang#100897 - RalfJung:const-not-to-mutable, r=lcnr
Browse files Browse the repository at this point in the history
extra sanity check against consts pointing to mutable memory

This should be both unreachable and redundant (since we already ensure that validation only reads from read-only memory, when validating consts), but I feel like we cannot be paranoid enough here, and also if this ever fails it'll be a nicer error than the "cannot read from mutable memory" error.
matthiaskrgr authored Aug 28, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents a8b63a4 + cb4cd73 commit 29fdd1c
Showing 7 changed files with 55 additions and 37 deletions.
72 changes: 45 additions & 27 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ use std::convert::TryFrom;
use std::fmt::Write;
use std::num::NonZeroUsize;

use rustc_ast::Mutability;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_middle::mir::interpret::InterpError;
@@ -423,34 +424,51 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
// Proceed recursively even for ZST, no reason to skip them!
// `!` is a ZST and we want to validate it.
if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr) {
// Special handling for pointers to statics (irrespective of their type).
// Let's see what kind of memory this points to.
let alloc_kind = self.ecx.tcx.try_get_global_alloc(alloc_id);
if let Some(GlobalAlloc::Static(did)) = alloc_kind {
assert!(!self.ecx.tcx.is_thread_local_static(did));
assert!(self.ecx.tcx.is_static(did));
if matches!(
self.ctfe_mode,
Some(CtfeValidationMode::Const { allow_static_ptrs: false, .. })
) {
// See const_eval::machine::MemoryExtra::can_access_statics for why
// this check is so important.
// This check is reachable when the const just referenced the static,
// but never read it (so we never entered `before_access_global`).
throw_validation_failure!(self.path,
{ "a {} pointing to a static variable", kind }
);
match alloc_kind {
Some(GlobalAlloc::Static(did)) => {
// Special handling for pointers to statics (irrespective of their type).
assert!(!self.ecx.tcx.is_thread_local_static(did));
assert!(self.ecx.tcx.is_static(did));
if matches!(
self.ctfe_mode,
Some(CtfeValidationMode::Const { allow_static_ptrs: false, .. })
) {
// See const_eval::machine::MemoryExtra::can_access_statics for why
// this check is so important.
// This check is reachable when the const just referenced the static,
// but never read it (so we never entered `before_access_global`).
throw_validation_failure!(self.path,
{ "a {} pointing to a static variable in a constant", kind }
);
}
// We skip recursively checking other statics. These statics must be sound by
// themselves, and the only way to get broken statics here is by using
// unsafe code.
// The reasons we don't check other statics is twofold. For one, in all
// sound cases, the static was already validated on its own, and second, we
// trigger cycle errors if we try to compute the value of the other static
// and that static refers back to us.
// We might miss const-invalid data,
// but things are still sound otherwise (in particular re: consts
// referring to statics).
return Ok(());
}
// We skip checking other statics. These statics must be sound by
// themselves, and the only way to get broken statics here is by using
// unsafe code.
// The reasons we don't check other statics is twofold. For one, in all
// sound cases, the static was already validated on its own, and second, we
// trigger cycle errors if we try to compute the value of the other static
// and that static refers back to us.
// We might miss const-invalid data,
// but things are still sound otherwise (in particular re: consts
// referring to statics).
return Ok(());
Some(GlobalAlloc::Memory(alloc)) => {
if alloc.inner().mutability == Mutability::Mut
&& matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. }))
{
// This should be unreachable, but if someone manages to copy a pointer
// out of a `static`, then that pointer might point to mutable memory,
// and we would catch that here.
throw_validation_failure!(self.path,
{ "a {} pointing to mutable memory in a constant", kind }
);
}
}
// Nothing to check for these.
None | Some(GlobalAlloc::Function(..) | GlobalAlloc::VTable(..)) => {}
}
}
let path = &self.path;
@@ -528,7 +546,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
}
ty::Ref(_, ty, mutbl) => {
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { .. }))
&& *mutbl == hir::Mutability::Mut
&& *mutbl == Mutability::Mut
{
// A mutable reference inside a const? That does not seem right (except if it is
// a ZST).
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-points-to-static.32bit.stderr
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const-points-to-static.rs:6:1
|
LL | const TEST: &u8 = &MY_STATIC;
| ^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable
| ^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant
|
= 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.
= note: the raw bytes of the constant (size: 4, align: 4) {
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-points-to-static.64bit.stderr
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const-points-to-static.rs:6:1
|
LL | const TEST: &u8 = &MY_STATIC;
| ^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable
| ^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant
|
= 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.
= note: the raw bytes of the constant (size: 8, align: 8) {
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const_refers_to_static2.rs:11:1
|
LL | const REF_INTERIOR_MUT: &usize = {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant
|
= 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.
= note: the raw bytes of the constant (size: 4, align: 4) {
@@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const_refers_to_static2.rs:18:1
|
LL | const READ_IMMUT: &usize = {
| ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable
| ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant
|
= 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.
= note: the raw bytes of the constant (size: 4, align: 4) {
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const_refers_to_static2.rs:11:1
|
LL | const REF_INTERIOR_MUT: &usize = {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant
|
= 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.
= note: the raw bytes of the constant (size: 8, align: 8) {
@@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const_refers_to_static2.rs:18:1
|
LL | const READ_IMMUT: &usize = {
| ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable
| ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant
|
= 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.
= note: the raw bytes of the constant (size: 8, align: 8) {
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const_refers_to_static_cross_crate.rs:12:1
|
LL | const SLICE_MUT: &[u8; 1] = {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable
| ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant
|
= 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.
= note: the raw bytes of the constant (size: 4, align: 4) {
@@ -19,7 +19,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const_refers_to_static_cross_crate.rs:17:1
|
LL | const U8_MUT: &u8 = {
| ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable
| ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant
|
= 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.
= note: the raw bytes of the constant (size: 4, align: 4) {
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const_refers_to_static_cross_crate.rs:12:1
|
LL | const SLICE_MUT: &[u8; 1] = {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable
| ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant
|
= 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.
= note: the raw bytes of the constant (size: 8, align: 8) {
@@ -19,7 +19,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/const_refers_to_static_cross_crate.rs:17:1
|
LL | const U8_MUT: &u8 = {
| ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable
| ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to a static variable in a constant
|
= 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.
= note: the raw bytes of the constant (size: 8, align: 8) {

0 comments on commit 29fdd1c

Please sign in to comment.