Mir: Abort on nounwind ABIs
Generate Abort instead of Resume terminators on nounwind ABIs. https://github.com/rust-lang/rust/issues/18510 Signed-off-by: David Henningsson <diwic@ubuntu.com>
This commit is contained in:
parent
dd6127e4af
commit
f536143ab6
6 changed files with 83 additions and 0 deletions
1
src/Cargo.lock
generated
1
src/Cargo.lock
generated
|
|
@ -1919,6 +1919,7 @@ dependencies = [
|
||||||
"log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc 0.0.0",
|
"rustc 0.0.0",
|
||||||
"rustc_apfloat 0.0.0",
|
"rustc_apfloat 0.0.0",
|
||||||
|
"rustc_back 0.0.0",
|
||||||
"rustc_const_eval 0.0.0",
|
"rustc_const_eval 0.0.0",
|
||||||
"rustc_const_math 0.0.0",
|
"rustc_const_math 0.0.0",
|
||||||
"rustc_data_structures 0.0.0",
|
"rustc_data_structures 0.0.0",
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ graphviz = { path = "../libgraphviz" }
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
log_settings = "0.1.1"
|
log_settings = "0.1.1"
|
||||||
rustc = { path = "../librustc" }
|
rustc = { path = "../librustc" }
|
||||||
|
rustc_back = { path = "../librustc_back" }
|
||||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
rustc_const_eval = { path = "../librustc_const_eval" }
|
||||||
rustc_const_math = { path = "../librustc_const_math" }
|
rustc_const_math = { path = "../librustc_const_math" }
|
||||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ use rustc::mir::visit::{MutVisitor, TyContext};
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
use rustc::util::nodemap::NodeMap;
|
use rustc::util::nodemap::NodeMap;
|
||||||
|
use rustc_back::PanicStrategy;
|
||||||
use rustc_const_eval::pattern::{BindingMode, PatternKind};
|
use rustc_const_eval::pattern::{BindingMode, PatternKind};
|
||||||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||||
use shim;
|
use shim;
|
||||||
|
|
@ -353,6 +354,27 @@ macro_rules! unpack {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn needs_abort_block<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
|
fn_id: ast::NodeId,
|
||||||
|
abi: Abi)
|
||||||
|
-> bool {
|
||||||
|
|
||||||
|
// Not callable from C, so we can safely unwind through these
|
||||||
|
if abi == Abi::Rust || abi == Abi::RustCall { return false; }
|
||||||
|
|
||||||
|
// We never unwind, so it's not relevant to stop an unwind
|
||||||
|
if tcx.sess.panic_strategy() != PanicStrategy::Unwind { return false; }
|
||||||
|
|
||||||
|
// We cannot add landing pads, so don't add one
|
||||||
|
if tcx.sess.no_landing_pads() { return false; }
|
||||||
|
|
||||||
|
// This is a special case: some functions have a C abi but are meant to
|
||||||
|
// unwind anyway. Don't stop them.
|
||||||
|
if tcx.has_attr(tcx.hir.local_def_id(fn_id), "unwind") { return false; }
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
/// the main entry point for building MIR for a function
|
/// the main entry point for building MIR for a function
|
||||||
|
|
||||||
|
|
@ -383,6 +405,11 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
|
||||||
let source_info = builder.source_info(span);
|
let source_info = builder.source_info(span);
|
||||||
let call_site_s = (call_site_scope, source_info);
|
let call_site_s = (call_site_scope, source_info);
|
||||||
unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, block, |builder| {
|
unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, block, |builder| {
|
||||||
|
|
||||||
|
if needs_abort_block(tcx, fn_id, abi) {
|
||||||
|
builder.schedule_abort();
|
||||||
|
}
|
||||||
|
|
||||||
let arg_scope_s = (arg_scope, source_info);
|
let arg_scope_s = (arg_scope, source_info);
|
||||||
unpack!(block = builder.in_scope(arg_scope_s, LintLevel::Inherited, block, |builder| {
|
unpack!(block = builder.in_scope(arg_scope_s, LintLevel::Inherited, block, |builder| {
|
||||||
builder.args_and_body(block, &arguments, arg_scope, &body.value)
|
builder.args_and_body(block, &arguments, arg_scope, &body.value)
|
||||||
|
|
|
||||||
|
|
@ -612,6 +612,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Schedule an abort block - this is used for some ABIs that cannot unwind
|
||||||
|
pub fn schedule_abort(&mut self) -> BasicBlock {
|
||||||
|
self.scopes[0].needs_cleanup = true;
|
||||||
|
let abortblk = self.cfg.start_new_cleanup_block();
|
||||||
|
let source_info = self.scopes[0].source_info(self.fn_span);
|
||||||
|
self.cfg.terminate(abortblk, source_info, TerminatorKind::Abort);
|
||||||
|
self.cached_resume_block = Some(abortblk);
|
||||||
|
abortblk
|
||||||
|
}
|
||||||
|
|
||||||
// Scheduling drops
|
// Scheduling drops
|
||||||
// ================
|
// ================
|
||||||
/// Indicates that `place` should be dropped on exit from
|
/// Indicates that `place` should be dropped on exit from
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ extern crate rustc_errors;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
extern crate syntax_pos;
|
extern crate syntax_pos;
|
||||||
|
extern crate rustc_back;
|
||||||
extern crate rustc_const_math;
|
extern crate rustc_const_math;
|
||||||
extern crate rustc_const_eval;
|
extern crate rustc_const_eval;
|
||||||
extern crate core; // for NonZero
|
extern crate core; // for NonZero
|
||||||
|
|
|
||||||
43
src/test/run-pass/abort-on-c-abi.rs
Normal file
43
src/test/run-pass/abort-on-c-abi.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
// Copyright 2012-2014 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.
|
||||||
|
|
||||||
|
// Since we mark some ABIs as "nounwind" to LLVM, we must make sure that
|
||||||
|
// we never unwind through them.
|
||||||
|
|
||||||
|
// ignore-emscripten no processes
|
||||||
|
|
||||||
|
use std::{env, panic};
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::io;
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
|
extern "C" fn panic_in_ffi() {
|
||||||
|
panic!("Test");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
let _ = panic::catch_unwind(|| { panic_in_ffi(); });
|
||||||
|
// The process should have aborted by now.
|
||||||
|
io::stdout().write(b"This should never be printed.\n");
|
||||||
|
let _ = io::stdout().flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
if args.len() > 1 && args[1] == "test" {
|
||||||
|
return test();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut p = Command::new(&args[0])
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.arg("test").spawn().unwrap();
|
||||||
|
assert!(!p.wait().unwrap().success());
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue