Skip to content

Commit

Permalink
detect consts that reference extern statics
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Jan 6, 2024
1 parent aee26a8 commit c7cca7c
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 51 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ const_eval_upcast_mismatch =
const_eval_validation_box_to_static = {$front_matter}: encountered a box pointing to a static variable in a constant
const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty}
const_eval_validation_const_ref_to_extern = {$front_matter}: encountered reference to `extern` static in `const`
const_eval_validation_const_ref_to_mutable = {$front_matter}: encountered reference to mutable memory in `const`
const_eval_validation_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance)
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_const_eval/src/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,15 +384,18 @@ pub fn const_validate_mplace<'mir, 'tcx>(
// Promoteds in statics are consts that re allowed to point to statics.
CtfeValidationMode::Const {
allow_immutable_unsafe_cell: false,
allow_static_ptrs: true,
allow_extern_static_ptrs: true,
}
}
Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static`
None => {
// In normal `const` (not promoted), the outermost allocation is always only copied,
// so having `UnsafeCell` in there is okay despite them being in immutable memory.
let allow_immutable_unsafe_cell = cid.promoted.is_none() && !inner;
CtfeValidationMode::Const { allow_immutable_unsafe_cell, allow_static_ptrs: false }
CtfeValidationMode::Const {
allow_immutable_unsafe_cell,
allow_extern_static_ptrs: false,
}
}
};
ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_const_eval/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
PointerAsInt { .. } => const_eval_validation_pointer_as_int,
PartialPointer => const_eval_validation_partial_pointer,
ConstRefToMutable => const_eval_validation_const_ref_to_mutable,
ConstRefToExtern => const_eval_validation_const_ref_to_extern,
MutableRefInConst => const_eval_validation_mutable_ref_in_const,
MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
NullFnPtr => const_eval_validation_null_fn_ptr,
Expand Down Expand Up @@ -767,6 +768,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
| PtrToStatic { .. }
| MutableRefInConst
| ConstRefToMutable
| ConstRefToExtern
| MutableRefToImmutable
| NullFnPtr
| NeverVal
Expand Down
14 changes: 12 additions & 2 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ pub enum CtfeValidationMode {
/// `allow_immutable_unsafe_cell` says whether we allow `UnsafeCell` in immutable memory (which is the
/// case for the top-level allocation of a `const`, where this is fine because the allocation will be
/// copied at each use site).
Const { allow_immutable_unsafe_cell: bool, allow_static_ptrs: bool },
Const { allow_immutable_unsafe_cell: bool, allow_extern_static_ptrs: bool },
}

impl CtfeValidationMode {
Expand Down Expand Up @@ -488,13 +488,23 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
// This could miss some UB, but that's fine.
return Ok(());
}
Some(CtfeValidationMode::Const { .. }) => {
Some(CtfeValidationMode::Const {
allow_extern_static_ptrs, ..
}) => {
// For consts on the other hand we have to recursively check;
// pattern matching assumes a valid value. However we better make
// sure this is not mutable.
if is_mut {
throw_validation_failure!(self.path, ConstRefToMutable);
}
if self.ecx.tcx.is_foreign_item(did) {
if !allow_extern_static_ptrs {
throw_validation_failure!(self.path, ConstRefToExtern);
} else {
// We can't validate this...
return Ok(());
}
}
}
None => {}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/mir/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ pub enum ValidationErrorKind<'tcx> {
PtrToStatic { ptr_kind: PointerKind },
MutableRefInConst,
ConstRefToMutable,
ConstRefToExtern,
MutableRefToImmutable,
UnsafeCellInImmutable,
NullFnPtr,
Expand Down
43 changes: 38 additions & 5 deletions tests/ui/consts/const_refs_to_static_fail_invalid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,49 @@
// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
#![feature(const_refs_to_static)]

static S: i8 = 10;
fn invalid() {
static S: i8 = 10;

const C: &bool = unsafe { std::mem::transmute(&S) };
//~^ERROR: undefined behavior
//~| expected a boolean
const C: &bool = unsafe { std::mem::transmute(&S) };
//~^ERROR: undefined behavior
//~| expected a boolean

fn main() {
// This must be rejected here (or earlier), since it's not a valid `&bool`.
match &true {
C => {} //~ERROR: could not evaluate constant pattern
_ => {}
}
}

fn extern_() {
extern "C" {
static S: i8;
}

const C: &i8 = unsafe { &S };
//~^ERROR: undefined behavior
//~| `extern` static

// This must be rejected here (or earlier), since the pattern cannot be read.
match &0 {
C => {} //~ERROR: could not evaluate constant pattern
_ => {}
}
}

fn mutable() {
static mut S_MUT: i32 = 0;

const C: &i32 = unsafe { &S_MUT };
//~^ERROR: undefined behavior
//~| encountered reference to mutable memory

// This *must not build*, the constant we are matching against
// could change its value!
match &42 {
C => {}, //~ERROR: could not evaluate constant pattern
_ => {},
}
}

fn main() {}
42 changes: 38 additions & 4 deletions tests/ui/consts/const_refs_to_static_fail_invalid.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0080]: it is undefined behavior to use this value
--> $DIR/const_refs_to_static_fail_invalid.rs:7:1
--> $DIR/const_refs_to_static_fail_invalid.rs:8:5
|
LL | const C: &bool = unsafe { std::mem::transmute(&S) };
| ^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered 0x0a, but expected a boolean
LL | const C: &bool = unsafe { std::mem::transmute(&S) };
| ^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered 0x0a, but expected a boolean
|
= 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: $SIZE, align: $ALIGN) {
Expand All @@ -12,9 +12,43 @@ LL | const C: &bool = unsafe { std::mem::transmute(&S) };
error: could not evaluate constant pattern
--> $DIR/const_refs_to_static_fail_invalid.rs:14:9
|
LL | C => {}
| ^

error[E0080]: it is undefined behavior to use this value
--> $DIR/const_refs_to_static_fail_invalid.rs:24:5
|
LL | const C: &i8 = unsafe { &S };
| ^^^^^^^^^^^^ constructing invalid value: encountered reference to `extern` static in `const`
|
= 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: $SIZE, align: $ALIGN) {
HEX_DUMP
}

error: could not evaluate constant pattern
--> $DIR/const_refs_to_static_fail_invalid.rs:30:9
|
LL | C => {}
| ^

error[E0080]: it is undefined behavior to use this value
--> $DIR/const_refs_to_static_fail_invalid.rs:38:5
|
LL | const C: &i32 = unsafe { &S_MUT };
| ^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const`
|
= 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: $SIZE, align: $ALIGN) {
HEX_DUMP
}

error: could not evaluate constant pattern
--> $DIR/const_refs_to_static_fail_invalid.rs:45:9
|
LL | C => {},
| ^

error: aborting due to 2 previous errors
error: aborting due to 6 previous errors

For more information about this error, try `rustc --explain E0080`.
18 changes: 0 additions & 18 deletions tests/ui/consts/const_refs_to_static_fail_pattern.rs

This file was deleted.

20 changes: 0 additions & 20 deletions tests/ui/consts/const_refs_to_static_fail_pattern.stderr

This file was deleted.

0 comments on commit c7cca7c

Please sign in to comment.