Skip to content

Commit f536143

Browse files
committed
Mir: Abort on nounwind ABIs
Generate Abort instead of Resume terminators on nounwind ABIs. #18510 Signed-off-by: David Henningsson <[email protected]>
1 parent dd6127e commit f536143

File tree

6 files changed

+83
-0
lines changed

6 files changed

+83
-0
lines changed

src/Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/librustc_mir/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ graphviz = { path = "../libgraphviz" }
1414
log = "0.3"
1515
log_settings = "0.1.1"
1616
rustc = { path = "../librustc" }
17+
rustc_back = { path = "../librustc_back" }
1718
rustc_const_eval = { path = "../librustc_const_eval" }
1819
rustc_const_math = { path = "../librustc_const_math" }
1920
rustc_data_structures = { path = "../librustc_data_structures" }

src/librustc_mir/build/mod.rs

+27
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use rustc::mir::visit::{MutVisitor, TyContext};
2020
use rustc::ty::{self, Ty, TyCtxt};
2121
use rustc::ty::subst::Substs;
2222
use rustc::util::nodemap::NodeMap;
23+
use rustc_back::PanicStrategy;
2324
use rustc_const_eval::pattern::{BindingMode, PatternKind};
2425
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
2526
use shim;
@@ -353,6 +354,27 @@ macro_rules! unpack {
353354
};
354355
}
355356

357+
fn needs_abort_block<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
358+
fn_id: ast::NodeId,
359+
abi: Abi)
360+
-> bool {
361+
362+
// Not callable from C, so we can safely unwind through these
363+
if abi == Abi::Rust || abi == Abi::RustCall { return false; }
364+
365+
// We never unwind, so it's not relevant to stop an unwind
366+
if tcx.sess.panic_strategy() != PanicStrategy::Unwind { return false; }
367+
368+
// We cannot add landing pads, so don't add one
369+
if tcx.sess.no_landing_pads() { return false; }
370+
371+
// This is a special case: some functions have a C abi but are meant to
372+
// unwind anyway. Don't stop them.
373+
if tcx.has_attr(tcx.hir.local_def_id(fn_id), "unwind") { return false; }
374+
375+
return true;
376+
}
377+
356378
///////////////////////////////////////////////////////////////////////////
357379
/// the main entry point for building MIR for a function
358380
@@ -383,6 +405,11 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
383405
let source_info = builder.source_info(span);
384406
let call_site_s = (call_site_scope, source_info);
385407
unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, block, |builder| {
408+
409+
if needs_abort_block(tcx, fn_id, abi) {
410+
builder.schedule_abort();
411+
}
412+
386413
let arg_scope_s = (arg_scope, source_info);
387414
unpack!(block = builder.in_scope(arg_scope_s, LintLevel::Inherited, block, |builder| {
388415
builder.args_and_body(block, &arguments, arg_scope, &body.value)

src/librustc_mir/build/scope.rs

+10
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
612612
}
613613
}
614614

615+
// Schedule an abort block - this is used for some ABIs that cannot unwind
616+
pub fn schedule_abort(&mut self) -> BasicBlock {
617+
self.scopes[0].needs_cleanup = true;
618+
let abortblk = self.cfg.start_new_cleanup_block();
619+
let source_info = self.scopes[0].source_info(self.fn_span);
620+
self.cfg.terminate(abortblk, source_info, TerminatorKind::Abort);
621+
self.cached_resume_block = Some(abortblk);
622+
abortblk
623+
}
624+
615625
// Scheduling drops
616626
// ================
617627
/// Indicates that `place` should be dropped on exit from

src/librustc_mir/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ extern crate rustc_errors;
4949
#[macro_use]
5050
extern crate syntax;
5151
extern crate syntax_pos;
52+
extern crate rustc_back;
5253
extern crate rustc_const_math;
5354
extern crate rustc_const_eval;
5455
extern crate core; // for NonZero

src/test/run-pass/abort-on-c-abi.rs

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2012-2014 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+
// Since we mark some ABIs as "nounwind" to LLVM, we must make sure that
12+
// we never unwind through them.
13+
14+
// ignore-emscripten no processes
15+
16+
use std::{env, panic};
17+
use std::io::prelude::*;
18+
use std::io;
19+
use std::process::{Command, Stdio};
20+
21+
extern "C" fn panic_in_ffi() {
22+
panic!("Test");
23+
}
24+
25+
fn test() {
26+
let _ = panic::catch_unwind(|| { panic_in_ffi(); });
27+
// The process should have aborted by now.
28+
io::stdout().write(b"This should never be printed.\n");
29+
let _ = io::stdout().flush();
30+
}
31+
32+
fn main() {
33+
let args: Vec<String> = env::args().collect();
34+
if args.len() > 1 && args[1] == "test" {
35+
return test();
36+
}
37+
38+
let mut p = Command::new(&args[0])
39+
.stdout(Stdio::piped())
40+
.stdin(Stdio::piped())
41+
.arg("test").spawn().unwrap();
42+
assert!(!p.wait().unwrap().success());
43+
}

0 commit comments

Comments
 (0)