Skip to content

Commit

Permalink
panic when instantiating an uninhabited type via mem::{uninitialized,…
Browse files Browse the repository at this point in the history
…zeroed}
  • Loading branch information
japaric authored and RalfJung committed Sep 30, 2018
1 parent 1886d5f commit f9bbb5f
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 0 deletions.
49 changes: 49 additions & 0 deletions src/librustc_codegen_llvm/mir/block.rs
Expand Up @@ -463,6 +463,55 @@ impl FunctionCx<'a, 'll, 'tcx> {
return;
}

if (intrinsic == Some("init") || intrinsic == Some("uninit")) &&
bx.cx.layout_of(sig.output()).abi.is_uninhabited()
{
let loc = bx.sess().codemap().lookup_char_pos(span.lo());
let filename = Symbol::intern(&loc.file.name.to_string()).as_str();
let filename = C_str_slice(bx.cx, filename);
let line = C_u32(bx.cx, loc.line as u32);
let col = C_u32(bx.cx, loc.col.to_usize() as u32 + 1);
let align = tcx.data_layout.aggregate_align
.max(tcx.data_layout.i32_align)
.max(tcx.data_layout.pointer_align);

let str = if intrinsic == Some("init") {
"Attempted to instantiate an uninhabited type (e.g. `!`) \
using mem::zeroed()"
} else {
"Attempted to instantiate an uninhabited type (e.g. `!`) \
using mem::uninitialized()"
};
let msg_str = Symbol::intern(str).as_str();
let msg_str = C_str_slice(bx.cx, msg_str);
let msg_file_line_col = C_struct(bx.cx,
&[msg_str, filename, line, col],
false);
let msg_file_line_col = consts::addr_of(bx.cx,
msg_file_line_col,
align,
Some("panic_loc"));

// Obtain the panic entry point.
let def_id =
common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
let instance = ty::Instance::mono(bx.tcx(), def_id);
let fn_ty = FnType::of_instance(bx.cx, &instance);
let llfn = callee::get_fn(bx.cx, instance);

// Codegen the actual panic invoke/call.
do_call(
self,
bx,
fn_ty,
llfn,
&[msg_file_line_col],
destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
cleanup,
);
return;
}

let extra_args = &args[sig.inputs().len()..];
let extra_args = extra_args.iter().map(|op_arg| {
let op_ty = op_arg.ty(self.mir, bx.tcx());
Expand Down
8 changes: 8 additions & 0 deletions src/librustc_target/abi/mod.rs
Expand Up @@ -802,6 +802,14 @@ impl Abi {
_ => false,
}
}

/// Returns true if this is an uninhabited type
pub fn is_uninhabited(&self) -> bool {
match *self {
Abi::Uninhabited => true,
_ => false,
}
}
}

#[derive(PartialEq, Eq, Hash, Debug)]
Expand Down
31 changes: 31 additions & 0 deletions src/test/run-pass/panic-uninitialized-zeroed.rs
@@ -0,0 +1,31 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results
// in a runtime panic.

#![feature(never_type)]

use std::{mem, panic};

struct Foo {
x: u8,
y: !,
}

fn main() {
unsafe {
panic::catch_unwind(|| mem::uninitialized::<!>()).is_err();
panic::catch_unwind(|| mem::zeroed::<!>()).is_err();

panic::catch_unwind(|| mem::uninitialized::<Foo>()).is_err();
panic::catch_unwind(|| mem::zeroed::<Foo>()).is_err();
}
}

0 comments on commit f9bbb5f

Please sign in to comment.