Skip to content

Commit 96572cb

Browse files
committed
panic when instantiating an uninhabited type via mem::{uninitialized,zeroed}
1 parent 851acdd commit 96572cb

File tree

3 files changed

+88
-0
lines changed

3 files changed

+88
-0
lines changed

src/librustc_codegen_llvm/mir/block.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,55 @@ impl FunctionCx<'a, 'll, 'tcx> {
463463
return;
464464
}
465465

466+
if (intrinsic == Some("init") || intrinsic == Some("uninit")) &&
467+
bx.cx.layout_of(sig.output()).abi.is_uninhabited()
468+
{
469+
let loc = bx.sess().codemap().lookup_char_pos(span.lo());
470+
let filename = Symbol::intern(&loc.file.name.to_string()).as_str();
471+
let filename = C_str_slice(bx.cx, filename);
472+
let line = C_u32(bx.cx, loc.line as u32);
473+
let col = C_u32(bx.cx, loc.col.to_usize() as u32 + 1);
474+
let align = tcx.data_layout.aggregate_align
475+
.max(tcx.data_layout.i32_align)
476+
.max(tcx.data_layout.pointer_align);
477+
478+
let str = if intrinsic == Some("init") {
479+
"Attempted to instantiate an uninhabited type (e.g. `!`) \
480+
using mem::zeroed()"
481+
} else {
482+
"Attempted to instantiate an uninhabited type (e.g. `!`) \
483+
using mem::uninitialized()"
484+
};
485+
let msg_str = Symbol::intern(str).as_str();
486+
let msg_str = C_str_slice(bx.cx, msg_str);
487+
let msg_file_line_col = C_struct(bx.cx,
488+
&[msg_str, filename, line, col],
489+
false);
490+
let msg_file_line_col = consts::addr_of(bx.cx,
491+
msg_file_line_col,
492+
align,
493+
Some("panic_loc"));
494+
495+
// Obtain the panic entry point.
496+
let def_id =
497+
common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
498+
let instance = ty::Instance::mono(bx.tcx(), def_id);
499+
let fn_ty = FnType::of_instance(bx.cx, &instance);
500+
let llfn = callee::get_fn(bx.cx, instance);
501+
502+
// Codegen the actual panic invoke/call.
503+
do_call(
504+
self,
505+
bx,
506+
fn_ty,
507+
llfn,
508+
&[msg_file_line_col],
509+
destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
510+
cleanup,
511+
);
512+
return;
513+
}
514+
466515
let extra_args = &args[sig.inputs().len()..];
467516
let extra_args = extra_args.iter().map(|op_arg| {
468517
let op_ty = op_arg.ty(self.mir, bx.tcx());

src/librustc_target/abi/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,14 @@ impl Abi {
802802
_ => false,
803803
}
804804
}
805+
806+
/// Returns true if this is an uninhabited type
807+
pub fn is_uninhabited(&self) -> bool {
808+
match *self {
809+
Abi::Uninhabited => true,
810+
_ => false,
811+
}
812+
}
805813
}
806814

807815
#[derive(PartialEq, Eq, Hash, Debug)]
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results
12+
// in a runtime panic.
13+
14+
#![feature(never_type)]
15+
16+
use std::{mem, panic};
17+
18+
struct Foo {
19+
x: u8,
20+
y: !,
21+
}
22+
23+
fn main() {
24+
unsafe {
25+
panic::catch_unwind(|| mem::uninitialized::<!>()).is_err();
26+
panic::catch_unwind(|| mem::zeroed::<!>()).is_err();
27+
28+
panic::catch_unwind(|| mem::uninitialized::<Foo>()).is_err();
29+
panic::catch_unwind(|| mem::zeroed::<Foo>()).is_err();
30+
}
31+
}

0 commit comments

Comments
 (0)