Skip to content

Commit 77f8c3c

Browse files
committed
detect consts that reference extern statics
1 parent 9c0623f commit 77f8c3c

File tree

9 files changed

+97
-51
lines changed

9 files changed

+97
-51
lines changed

compiler/rustc_const_eval/messages.ftl

+1
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ const_eval_upcast_mismatch =
412412
const_eval_validation_box_to_static = {$front_matter}: encountered a box pointing to a static variable in a constant
413413
const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty}
414414
415+
const_eval_validation_const_ref_to_extern = {$front_matter}: encountered reference to `extern` static in `const`
415416
const_eval_validation_const_ref_to_mutable = {$front_matter}: encountered reference to mutable memory in `const`
416417
417418
const_eval_validation_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance)

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -360,15 +360,18 @@ pub fn const_validate_mplace<'mir, 'tcx>(
360360
// Promoteds in statics are consts that re allowed to point to statics.
361361
CtfeValidationMode::Const {
362362
allow_immutable_unsafe_cell: false,
363-
allow_static_ptrs: true,
363+
allow_extern_static_ptrs: true,
364364
}
365365
}
366366
Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static`
367367
None => {
368368
// In normal `const` (not promoted), the outermost allocation is always only copied,
369369
// so having `UnsafeCell` in there is okay despite them being in immutable memory.
370370
let allow_immutable_unsafe_cell = cid.promoted.is_none() && !inner;
371-
CtfeValidationMode::Const { allow_immutable_unsafe_cell, allow_static_ptrs: false }
371+
CtfeValidationMode::Const {
372+
allow_immutable_unsafe_cell,
373+
allow_extern_static_ptrs: false,
374+
}
372375
}
373376
};
374377
ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;

compiler/rustc_const_eval/src/errors.rs

+2
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
612612
PointerAsInt { .. } => const_eval_validation_pointer_as_int,
613613
PartialPointer => const_eval_validation_partial_pointer,
614614
ConstRefToMutable => const_eval_validation_const_ref_to_mutable,
615+
ConstRefToExtern => const_eval_validation_const_ref_to_extern,
615616
MutableRefInConst => const_eval_validation_mutable_ref_in_const,
616617
MutableRefToImmutable => const_eval_validation_mutable_ref_to_immutable,
617618
NullFnPtr => const_eval_validation_null_fn_ptr,
@@ -767,6 +768,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
767768
| PtrToStatic { .. }
768769
| MutableRefInConst
769770
| ConstRefToMutable
771+
| ConstRefToExtern
770772
| MutableRefToImmutable
771773
| NullFnPtr
772774
| NeverVal

compiler/rustc_const_eval/src/interpret/validity.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ pub enum CtfeValidationMode {
133133
/// `allow_immutable_unsafe_cell` says whether we allow `UnsafeCell` in immutable memory (which is the
134134
/// case for the top-level allocation of a `const`, where this is fine because the allocation will be
135135
/// copied at each use site).
136-
Const { allow_immutable_unsafe_cell: bool, allow_static_ptrs: bool },
136+
Const { allow_immutable_unsafe_cell: bool, allow_extern_static_ptrs: bool },
137137
}
138138

139139
impl CtfeValidationMode {
@@ -488,13 +488,23 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
488488
// This could miss some UB, but that's fine.
489489
return Ok(());
490490
}
491-
Some(CtfeValidationMode::Const { .. }) => {
491+
Some(CtfeValidationMode::Const {
492+
allow_extern_static_ptrs, ..
493+
}) => {
492494
// For consts on the other hand we have to recursively check;
493495
// pattern matching assumes a valid value. However we better make
494496
// sure this is not mutable.
495497
if is_mut {
496498
throw_validation_failure!(self.path, ConstRefToMutable);
497499
}
500+
if self.ecx.tcx.is_foreign_item(did) {
501+
if !allow_extern_static_ptrs {
502+
throw_validation_failure!(self.path, ConstRefToExtern);
503+
} else {
504+
// We can't validate this...
505+
return Ok(());
506+
}
507+
}
498508
}
499509
None => {}
500510
}

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

+1
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ pub enum ValidationErrorKind<'tcx> {
418418
PtrToStatic { ptr_kind: PointerKind },
419419
MutableRefInConst,
420420
ConstRefToMutable,
421+
ConstRefToExtern,
421422
MutableRefToImmutable,
422423
UnsafeCellInImmutable,
423424
NullFnPtr,

tests/ui/consts/const_refs_to_static_fail_invalid.rs

+38-5
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,49 @@
22
// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP"
33
#![feature(const_refs_to_static)]
44

5-
static S: i8 = 10;
5+
fn invalid() {
6+
static S: i8 = 10;
67

7-
const C: &bool = unsafe { std::mem::transmute(&S) };
8-
//~^ERROR: undefined behavior
9-
//~| expected a boolean
8+
const C: &bool = unsafe { std::mem::transmute(&S) };
9+
//~^ERROR: undefined behavior
10+
//~| expected a boolean
1011

11-
fn main() {
1212
// This must be rejected here (or earlier), since it's not a valid `&bool`.
1313
match &true {
14+
C => {} //~ERROR: could not evaluate constant pattern
15+
_ => {}
16+
}
17+
}
18+
19+
fn extern_() {
20+
extern "C" {
21+
static S: i8;
22+
}
23+
24+
const C: &i8 = unsafe { &S };
25+
//~^ERROR: undefined behavior
26+
//~| `extern` static
27+
28+
// This must be rejected here (or earlier), since the pattern cannot be read.
29+
match &0 {
30+
C => {} //~ERROR: could not evaluate constant pattern
31+
_ => {}
32+
}
33+
}
34+
35+
fn mutable() {
36+
static mut S_MUT: i32 = 0;
37+
38+
const C: &i32 = unsafe { &S_MUT };
39+
//~^ERROR: undefined behavior
40+
//~| encountered reference to mutable memory
41+
42+
// This *must not build*, the constant we are matching against
43+
// could change its value!
44+
match &42 {
1445
C => {}, //~ERROR: could not evaluate constant pattern
1546
_ => {},
1647
}
1748
}
49+
50+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0080]: it is undefined behavior to use this value
2-
--> $DIR/const_refs_to_static_fail_invalid.rs:7:1
2+
--> $DIR/const_refs_to_static_fail_invalid.rs:8:5
33
|
4-
LL | const C: &bool = unsafe { std::mem::transmute(&S) };
5-
| ^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered 0x0a, but expected a boolean
4+
LL | const C: &bool = unsafe { std::mem::transmute(&S) };
5+
| ^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered 0x0a, but expected a boolean
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: $SIZE, align: $ALIGN) {
@@ -12,9 +12,43 @@ LL | const C: &bool = unsafe { std::mem::transmute(&S) };
1212
error: could not evaluate constant pattern
1313
--> $DIR/const_refs_to_static_fail_invalid.rs:14:9
1414
|
15+
LL | C => {}
16+
| ^
17+
18+
error[E0080]: it is undefined behavior to use this value
19+
--> $DIR/const_refs_to_static_fail_invalid.rs:24:5
20+
|
21+
LL | const C: &i8 = unsafe { &S };
22+
| ^^^^^^^^^^^^ constructing invalid value: encountered reference to `extern` static in `const`
23+
|
24+
= 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.
25+
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
26+
HEX_DUMP
27+
}
28+
29+
error: could not evaluate constant pattern
30+
--> $DIR/const_refs_to_static_fail_invalid.rs:30:9
31+
|
32+
LL | C => {}
33+
| ^
34+
35+
error[E0080]: it is undefined behavior to use this value
36+
--> $DIR/const_refs_to_static_fail_invalid.rs:38:5
37+
|
38+
LL | const C: &i32 = unsafe { &S_MUT };
39+
| ^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const`
40+
|
41+
= 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.
42+
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
43+
HEX_DUMP
44+
}
45+
46+
error: could not evaluate constant pattern
47+
--> $DIR/const_refs_to_static_fail_invalid.rs:45:9
48+
|
1549
LL | C => {},
1650
| ^
1751

18-
error: aborting due to 2 previous errors
52+
error: aborting due to 6 previous errors
1953

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

tests/ui/consts/const_refs_to_static_fail_pattern.rs

-18
This file was deleted.

tests/ui/consts/const_refs_to_static_fail_pattern.stderr

-20
This file was deleted.

0 commit comments

Comments
 (0)