Skip to content

Commit

Permalink
fix validating arrays of ZSTs
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Oct 2, 2018
1 parent de79ea6 commit 5c450de
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 19 deletions.
12 changes: 12 additions & 0 deletions src/librustc_mir/interpret/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,18 @@ impl MemPlace {
}

impl<'tcx> MPlaceTy<'tcx> {
/// Produces a MemPlace that works for ZST but nothing else
#[inline]
pub fn dangling(layout: TyLayout<'tcx>, cx: impl HasDataLayout) -> Self {
MPlaceTy {
mplace: MemPlace::from_scalar_ptr(
Scalar::from_uint(layout.align.abi(), cx.pointer_size()),
layout.align
),
layout
}
}

#[inline]
fn from_aligned_ptr(ptr: Pointer, layout: TyLayout<'tcx>) -> Self {
MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align), layout }
Expand Down
13 changes: 8 additions & 5 deletions src/librustc_mir/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,8 +365,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
// The fields don't need to correspond to any bit pattern of the union's fields.
// See https://github.com/rust-lang/rust/issues/32836#issuecomment-406875389
},
layout::FieldPlacement::Array { stride, .. } if !dest.layout.is_zst() => {
let dest = dest.to_mem_place(); // non-ZST array/slice/str cannot be immediate
layout::FieldPlacement::Array { stride, .. } => {
let dest = if dest.layout.is_zst() {
// it's a ZST, the memory content cannot matter
MPlaceTy::dangling(dest.layout, self)
} else {
// non-ZST array/slice/str cannot be immediate
dest.to_mem_place()
};
match dest.layout.ty.sty {
// Special handling for strings to verify UTF-8
ty::Str => {
Expand Down Expand Up @@ -429,9 +435,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
}
}
},
layout::FieldPlacement::Array { .. } => {
// An empty array. Nothing to do.
}
layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
for i in 0..offsets.len() {
let field = self.operand_field(dest, i as u64)?;
Expand Down
15 changes: 8 additions & 7 deletions src/test/ui/consts/const-eval/ub-uninhabit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,20 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

union Foo {
a: usize,
b: Bar,
c: &'static Bar,
}
#![feature(const_transmute)]

use std::mem;

#[derive(Copy, Clone)]
enum Bar {}

const BAD_BAD_BAD: Bar = unsafe { Foo { a: 1 }.b };
const BAD_BAD_BAD: Bar = unsafe { mem::transmute(()) };
//~^ ERROR this constant likely exhibits undefined behavior

const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
//~^ ERROR this constant likely exhibits undefined behavior

const BAD_BAD_REF: &Bar = unsafe { Foo { a: 1 }.c };
const BAD_BAD_ARRAY: [Bar; 1] = unsafe { mem::transmute(()) };
//~^ ERROR this constant likely exhibits undefined behavior

fn main() {
Expand Down
22 changes: 15 additions & 7 deletions src/test/ui/consts/const-eval/ub-uninhabit.stderr
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
error[E0080]: this constant likely exhibits undefined behavior
--> $DIR/ub-uninhabit.rs:20:1
--> $DIR/ub-uninhabit.rs:18:1
|
LL | const BAD_BAD_BAD: Bar = unsafe { Foo { a: 1 }.b };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type
LL | const BAD_BAD_BAD: Bar = unsafe { mem::transmute(()) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type
|
= 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

error[E0080]: this constant likely exhibits undefined behavior
--> $DIR/ub-uninhabit.rs:23:1
--> $DIR/ub-uninhabit.rs:21:1
|
LL | const BAD_BAD_REF: &Bar = unsafe { Foo { a: 1 }.c };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at .<deref>
LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at .<deref>
|
= 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

error: aborting due to 2 previous errors
error[E0080]: this constant likely exhibits undefined behavior
--> $DIR/ub-uninhabit.rs:24:1
|
LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { mem::transmute(()) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at [0]
|
= 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

error: aborting due to 3 previous errors

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

0 comments on commit 5c450de

Please sign in to comment.