detect consts that reference extern statics
This commit is contained in:
parent
9c0623fe8f
commit
77f8c3caea
9 changed files with 97 additions and 51 deletions
|
@ -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_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_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_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)
|
const_eval_validation_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance)
|
||||||
|
|
|
@ -360,7 +360,7 @@ pub fn const_validate_mplace<'mir, 'tcx>(
|
||||||
// Promoteds in statics are consts that re allowed to point to statics.
|
// Promoteds in statics are consts that re allowed to point to statics.
|
||||||
CtfeValidationMode::Const {
|
CtfeValidationMode::Const {
|
||||||
allow_immutable_unsafe_cell: false,
|
allow_immutable_unsafe_cell: false,
|
||||||
allow_static_ptrs: true,
|
allow_extern_static_ptrs: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static`
|
Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static`
|
||||||
|
@ -368,7 +368,10 @@ pub fn const_validate_mplace<'mir, 'tcx>(
|
||||||
// In normal `const` (not promoted), the outermost allocation is always only copied,
|
// 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.
|
// so having `UnsafeCell` in there is okay despite them being in immutable memory.
|
||||||
let allow_immutable_unsafe_cell = cid.promoted.is_none() && !inner;
|
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)?;
|
ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
|
||||||
|
|
|
@ -612,6 +612,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
|
||||||
PointerAsInt { .. } => const_eval_validation_pointer_as_int,
|
PointerAsInt { .. } => const_eval_validation_pointer_as_int,
|
||||||
PartialPointer => const_eval_validation_partial_pointer,
|
PartialPointer => const_eval_validation_partial_pointer,
|
||||||
ConstRefToMutable => const_eval_validation_const_ref_to_mutable,
|
ConstRefToMutable => const_eval_validation_const_ref_to_mutable,
|
||||||
|
ConstRefToExtern => const_eval_validation_const_ref_to_extern,
|
||||||
MutableRefInConst => const_eval_validation_mutable_ref_in_const,
|
MutableRefInConst => const_eval_validation_mutable_ref_in_const,
|
||||||
MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
|
MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
|
||||||
NullFnPtr => const_eval_validation_null_fn_ptr,
|
NullFnPtr => const_eval_validation_null_fn_ptr,
|
||||||
|
@ -767,6 +768,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
|
||||||
| PtrToStatic { .. }
|
| PtrToStatic { .. }
|
||||||
| MutableRefInConst
|
| MutableRefInConst
|
||||||
| ConstRefToMutable
|
| ConstRefToMutable
|
||||||
|
| ConstRefToExtern
|
||||||
| MutableRefToImmutable
|
| MutableRefToImmutable
|
||||||
| NullFnPtr
|
| NullFnPtr
|
||||||
| NeverVal
|
| NeverVal
|
||||||
|
|
|
@ -133,7 +133,7 @@ pub enum CtfeValidationMode {
|
||||||
/// `allow_immutable_unsafe_cell` says whether we allow `UnsafeCell` in immutable memory (which is the
|
/// `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
|
/// case for the top-level allocation of a `const`, where this is fine because the allocation will be
|
||||||
/// copied at each use site).
|
/// 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 {
|
impl CtfeValidationMode {
|
||||||
|
@ -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.
|
// This could miss some UB, but that's fine.
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
Some(CtfeValidationMode::Const { .. }) => {
|
Some(CtfeValidationMode::Const {
|
||||||
|
allow_extern_static_ptrs, ..
|
||||||
|
}) => {
|
||||||
// For consts on the other hand we have to recursively check;
|
// For consts on the other hand we have to recursively check;
|
||||||
// pattern matching assumes a valid value. However we better make
|
// pattern matching assumes a valid value. However we better make
|
||||||
// sure this is not mutable.
|
// sure this is not mutable.
|
||||||
if is_mut {
|
if is_mut {
|
||||||
throw_validation_failure!(self.path, ConstRefToMutable);
|
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 => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -418,6 +418,7 @@ pub enum ValidationErrorKind<'tcx> {
|
||||||
PtrToStatic { ptr_kind: PointerKind },
|
PtrToStatic { ptr_kind: PointerKind },
|
||||||
MutableRefInConst,
|
MutableRefInConst,
|
||||||
ConstRefToMutable,
|
ConstRefToMutable,
|
||||||
|
ConstRefToExtern,
|
||||||
MutableRefToImmutable,
|
MutableRefToImmutable,
|
||||||
UnsafeCellInImmutable,
|
UnsafeCellInImmutable,
|
||||||
NullFnPtr,
|
NullFnPtr,
|
||||||
|
|
|
@ -2,16 +2,49 @@
|
||||||
// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
|
// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
|
||||||
#![feature(const_refs_to_static)]
|
#![feature(const_refs_to_static)]
|
||||||
|
|
||||||
static S: i8 = 10;
|
fn invalid() {
|
||||||
|
static S: i8 = 10;
|
||||||
|
|
||||||
const C: &bool = unsafe { std::mem::transmute(&S) };
|
const C: &bool = unsafe { std::mem::transmute(&S) };
|
||||||
//~^ERROR: undefined behavior
|
//~^ERROR: undefined behavior
|
||||||
//~| expected a boolean
|
//~| expected a boolean
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// This must be rejected here (or earlier), since it's not a valid `&bool`.
|
// This must be rejected here (or earlier), since it's not a valid `&bool`.
|
||||||
match &true {
|
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
|
C => {}, //~ERROR: could not evaluate constant pattern
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error[E0080]: it is undefined behavior to use this value
|
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) };
|
LL | const C: &bool = unsafe { std::mem::transmute(&S) };
|
||||||
| ^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered 0x0a, but expected a boolean
|
| ^^^^^^^^^^^^^^ 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 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) {
|
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
|
||||||
|
@ -12,9 +12,43 @@ LL | const C: &bool = unsafe { std::mem::transmute(&S) };
|
||||||
error: could not evaluate constant pattern
|
error: could not evaluate constant pattern
|
||||||
--> $DIR/const_refs_to_static_fail_invalid.rs:14:9
|
--> $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 => {},
|
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`.
|
For more information about this error, try `rustc --explain E0080`.
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
|
|
||||||
// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
|
|
||||||
#![feature(const_refs_to_static)]
|
|
||||||
|
|
||||||
static mut S_MUT: i32 = 0;
|
|
||||||
|
|
||||||
const C: &i32 = unsafe { &S_MUT };
|
|
||||||
//~^ERROR: undefined behavior
|
|
||||||
//~| encountered reference to mutable memory
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// This *must not build*, the constant we are matching against
|
|
||||||
// could change its value!
|
|
||||||
match &42 {
|
|
||||||
C => {}, //~ERROR: could not evaluate constant pattern
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
error[E0080]: it is undefined behavior to use this value
|
|
||||||
--> $DIR/const_refs_to_static_fail_pattern.rs:7:1
|
|
||||||
|
|
|
||||||
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_pattern.rs:15:9
|
|
||||||
|
|
|
||||||
LL | C => {},
|
|
||||||
| ^
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0080`.
|
|
Loading…
Add table
Add a link
Reference in a new issue