Skip to content

Commit aea0509

Browse files
committed
detect consts that reference extern statics
1 parent aee26a8 commit aea0509

9 files changed

+97
-51
lines changed

compiler/rustc_const_eval/messages.ftl

+1
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ const_eval_validation_box_to_static = {$front_matter}: encountered a box pointin
413413
const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty}
414414
415415
const_eval_validation_const_ref_to_mutable = {$front_matter}: encountered reference to mutable memory in `const`
416+
const_eval_validation_const_ref_to_extern = {$front_matter}: encountered reference to `extern` static in `const`
416417
417418
const_eval_validation_dangling_box_no_provenance = {$front_matter}: encountered a dangling box ({$pointer} has no provenance)
418419
const_eval_validation_dangling_box_out_of_bounds = {$front_matter}: encountered a dangling box (going beyond the bounds of its allocation)

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -384,15 +384,18 @@ pub fn const_validate_mplace<'mir, 'tcx>(
384384
// Promoteds in statics are consts that re allowed to point to statics.
385385
CtfeValidationMode::Const {
386386
allow_immutable_unsafe_cell: false,
387-
allow_static_ptrs: true,
387+
allow_extern_static_ptrs: true,
388388
}
389389
}
390390
Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static`
391391
None => {
392392
// In normal `const` (not promoted), the outermost allocation is always only copied,
393393
// so having `UnsafeCell` in there is okay despite them being in immutable memory.
394394
let allow_immutable_unsafe_cell = cid.promoted.is_none() && !inner;
395-
CtfeValidationMode::Const { allow_immutable_unsafe_cell, allow_static_ptrs: false }
395+
CtfeValidationMode::Const {
396+
allow_immutable_unsafe_cell,
397+
allow_extern_static_ptrs: false,
398+
}
396399
}
397400
};
398401
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
@@ -426,6 +426,7 @@ pub enum ValidationErrorKind<'tcx> {
426426
PtrToStatic { ptr_kind: PointerKind },
427427
MutableRefInConst,
428428
ConstRefToMutable,
429+
ConstRefToExtern,
429430
MutableRefToImmutable,
430431
UnsafeCellInImmutable,
431432
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)