Skip to content

Commit fa01e04

Browse files
committed
fix validation error on non-integer enum discriminants
1 parent 6d24b37 commit fa01e04

19 files changed

+79
-58
lines changed

src/librustc/mir/interpret/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use ty::{Ty, layout};
1515
use ty::layout::{Size, Align, LayoutError};
1616
use rustc_target::spec::abi::Abi;
1717

18-
use super::Pointer;
18+
use super::{Pointer, Scalar};
1919

2020
use backtrace::Backtrace;
2121

@@ -240,7 +240,7 @@ pub enum EvalErrorKind<'tcx, O> {
240240
InvalidMemoryAccess,
241241
InvalidFunctionPointer,
242242
InvalidBool,
243-
InvalidDiscriminant(u128),
243+
InvalidDiscriminant(Scalar),
244244
PointerOutOfBounds {
245245
ptr: Pointer,
246246
access: bool,

src/librustc/mir/interpret/value.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![allow(unknown_lints)]
11+
use std::fmt;
1212

1313
use ty::layout::{HasDataLayout, Size};
1414
use ty::subst::Substs;
@@ -99,6 +99,15 @@ pub enum Scalar<Tag=(), Id=AllocId> {
9999
Ptr(Pointer<Tag, Id>),
100100
}
101101

102+
impl<Tag> fmt::Display for Scalar<Tag> {
103+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104+
match self {
105+
Scalar::Ptr(_) => write!(f, "a pointer"),
106+
Scalar::Bits { bits, .. } => write!(f, "{}", bits),
107+
}
108+
}
109+
}
110+
102111
impl<'tcx> Scalar<()> {
103112
#[inline]
104113
pub fn with_default_tag<Tag>(self) -> Scalar<Tag>

src/librustc_mir/interpret/operand.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//! All high-level functions to read from memory work on operands as sources.
1313
1414
use std::convert::TryInto;
15+
use std::fmt;
1516

1617
use rustc::{mir, ty};
1718
use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt};
@@ -36,6 +37,15 @@ impl<Tag> From<Scalar<Tag>> for ScalarMaybeUndef<Tag> {
3637
}
3738
}
3839

40+
impl<Tag> fmt::Display for ScalarMaybeUndef<Tag> {
41+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42+
match self {
43+
ScalarMaybeUndef::Undef => write!(f, "uninitialized bytes"),
44+
ScalarMaybeUndef::Scalar(s) => write!(f, "{}", s),
45+
}
46+
}
47+
}
48+
3949
impl<'tcx> ScalarMaybeUndef<()> {
4050
#[inline]
4151
pub fn with_default_tag<Tag>(self) -> ScalarMaybeUndef<Tag>
@@ -732,8 +742,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
732742
Ok(match rval.layout.variants {
733743
layout::Variants::Single { .. } => bug!(),
734744
layout::Variants::Tagged { .. } => {
745+
let bits_discr = match raw_discr.to_bits(discr_val.layout.size) {
746+
Ok(raw_discr) => raw_discr,
747+
Err(_) => return err!(InvalidDiscriminant(raw_discr.erase_tag())),
748+
};
735749
let real_discr = if discr_val.layout.ty.is_signed() {
736-
let i = raw_discr.to_bits(discr_val.layout.size)? as i128;
750+
let i = bits_discr as i128;
737751
// going from layout tag type to typeck discriminant type
738752
// requires first sign extending with the layout discriminant
739753
let shift = 128 - discr_val.layout.size.bits();
@@ -748,15 +762,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
748762
let truncatee = sexted as u128;
749763
(truncatee << shift) >> shift
750764
} else {
751-
raw_discr.to_bits(discr_val.layout.size)?
765+
bits_discr
752766
};
753767
// Make sure we catch invalid discriminants
754768
let index = rval.layout.ty
755769
.ty_adt_def()
756770
.expect("tagged layout for non adt")
757771
.discriminants(self.tcx.tcx)
758772
.position(|var| var.val == real_discr)
759-
.ok_or_else(|| EvalErrorKind::InvalidDiscriminant(real_discr))?;
773+
.ok_or_else(|| EvalErrorKind::InvalidDiscriminant(raw_discr.erase_tag()))?;
760774
(real_discr, index)
761775
},
762776
layout::Variants::NicheFilling {

src/librustc_mir/interpret/validity.rs

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use rustc::mir::interpret::{
2020
};
2121

2222
use super::{
23-
OpTy, MPlaceTy, Machine, EvalContext, ScalarMaybeUndef, ValueVisitor
23+
OpTy, MPlaceTy, Machine, EvalContext, ValueVisitor
2424
};
2525

2626
macro_rules! validation_failure {
@@ -122,17 +122,6 @@ fn path_format(path: &Vec<PathElem>) -> String {
122122
out
123123
}
124124

125-
fn scalar_format<Tag>(value: ScalarMaybeUndef<Tag>) -> String {
126-
match value {
127-
ScalarMaybeUndef::Undef =>
128-
"uninitialized bytes".to_owned(),
129-
ScalarMaybeUndef::Scalar(Scalar::Ptr(_)) =>
130-
"a pointer".to_owned(),
131-
ScalarMaybeUndef::Scalar(Scalar::Bits { bits, .. }) =>
132-
bits.to_string(),
133-
}
134-
}
135-
136125
struct ValidityVisitor<'rt, 'a, 'tcx: 'a+'rt, Tag: 'static> {
137126
op: OpTy<'tcx, Tag>,
138127
/// The `path` may be pushed to, but the part that is present when a function
@@ -240,7 +229,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
240229
Err(err) => match err.kind {
241230
EvalErrorKind::InvalidDiscriminant(val) =>
242231
validation_failure!(
243-
format!("invalid enum discriminant {}", val), self.path
232+
val, self.path, "a valid enum discriminant"
244233
),
245234
_ => Err(err),
246235
}
@@ -258,12 +247,12 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
258247
ty::Bool => {
259248
let value = value.to_scalar_or_undef();
260249
try_validation!(value.to_bool(),
261-
scalar_format(value), self.path, "a boolean");
250+
value, self.path, "a boolean");
262251
},
263252
ty::Char => {
264253
let value = value.to_scalar_or_undef();
265254
try_validation!(value.to_char(),
266-
scalar_format(value), self.path, "a valid unicode codepoint");
255+
value, self.path, "a valid unicode codepoint");
267256
},
268257
ty::Float(_) | ty::Int(_) | ty::Uint(_) => {
269258
// NOTE: Keep this in sync with the array optimization for int/float
@@ -273,7 +262,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
273262
if self.const_mode {
274263
// Integers/floats in CTFE: Must be scalar bits, pointers are dangerous
275264
try_validation!(value.to_bits(size),
276-
scalar_format(value), self.path, "initialized plain bits");
265+
value, self.path, "initialized plain bits");
277266
} else {
278267
// At run-time, for now, we accept *anything* for these types, including
279268
// undef. We should fix that, but let's start low.
@@ -389,9 +378,9 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
389378
ty::FnPtr(_sig) => {
390379
let value = value.to_scalar_or_undef();
391380
let ptr = try_validation!(value.to_ptr(),
392-
scalar_format(value), self.path, "a pointer");
381+
value, self.path, "a pointer");
393382
let _fn = try_validation!(ectx.memory.get_fn(ptr),
394-
scalar_format(value), self.path, "a function pointer");
383+
value, self.path, "a function pointer");
395384
// FIXME: Check if the signature matches
396385
}
397386
// This should be all the primitive types
@@ -423,7 +412,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
423412
}
424413
// At least one value is excluded. Get the bits.
425414
let value = try_validation!(value.not_undef(),
426-
scalar_format(value), self.path,
415+
value, self.path,
427416
format!("something in the range {:?}", layout.valid_range));
428417
let bits = match value {
429418
Scalar::Ptr(ptr) => {

src/test/ui/consts/const-eval/double_check2.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | / static FOO: (&Foo, &Bar) = unsafe {( //~ undefined behavior
55
LL | | Union { u8: &BAR }.foo,
66
LL | | Union { u8: &BAR }.bar,
77
LL | | )};
8-
| |___^ type validation failed: encountered invalid enum discriminant 5 at .1.<deref>
8+
| |___^ type validation failed: encountered 5 at .1.<deref>, but expected a valid enum discriminant
99
|
1010
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
1111

src/test/ui/consts/const-eval/ub-enum.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![allow(const_err)] // make sure we cannot allow away the errors tested here
12+
1113
#[repr(usize)]
1214
#[derive(Copy, Clone)]
1315
enum Enum {

src/test/ui/consts/const-eval/ub-enum.stderr

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
error[E0080]: it is undefined behavior to use this value
2-
--> $DIR/ub-enum.rs:22:1
2+
--> $DIR/ub-enum.rs:24:1
33
|
44
LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { a: &1 }.b };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer enum discriminant
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant
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 rust compiler repository if you believe it should not be considered undefined behavior
88

99
error[E0080]: it is undefined behavior to use this value
10-
--> $DIR/ub-enum.rs:35:1
10+
--> $DIR/ub-enum.rs:37:1
1111
|
1212
LL | const BAD_ENUM2 : Enum2 = unsafe { TransmuteEnum2 { a: 0 }.b };
13-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid enum discriminant 0
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant
1414
|
1515
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
1616

1717
error[E0080]: it is undefined behavior to use this value
18-
--> $DIR/ub-enum.rs:45:1
18+
--> $DIR/ub-enum.rs:47:1
1919
|
2020
LL | const BAD_ENUM_CHAR : Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
2121
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at .Some.0.1, but expected something in the range 0..=1114111

src/test/ui/consts/const-eval/ub-nonnull.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// except according to those terms.
1010

1111
#![feature(const_transmute)]
12+
#![allow(const_err)] // make sure we cannot allow away the errors tested here
1213

1314
use std::mem;
1415
use std::ptr::NonNull;

src/test/ui/consts/const-eval/ub-nonnull.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
error[E0080]: it is undefined behavior to use this value
2-
--> $DIR/ub-nonnull.rs:17:1
2+
--> $DIR/ub-nonnull.rs:18:1
33
|
44
LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
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 rust compiler repository if you believe it should not be considered undefined behavior
88

99
error[E0080]: it is undefined behavior to use this value
10-
--> $DIR/ub-nonnull.rs:20:1
10+
--> $DIR/ub-nonnull.rs:21:1
1111
|
1212
LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
1414
|
1515
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
1616

1717
error[E0080]: it is undefined behavior to use this value
18-
--> $DIR/ub-nonnull.rs:22:1
18+
--> $DIR/ub-nonnull.rs:23:1
1919
|
2020
LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
2121
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1

src/test/ui/consts/const-eval/ub-ref.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// except according to those terms.
1010

1111
#![feature(const_transmute)]
12+
#![allow(const_err)] // make sure we cannot allow away the errors tested here
1213

1314
use std::mem;
1415

0 commit comments

Comments
 (0)