101 lines
2.4 KiB
Rust
101 lines
2.4 KiB
Rust
//@ run-pass
|
|
//@ revisions: current next
|
|
//@ ignore-compare-mode-next-solver (explicit revisions)
|
|
//@[next] compile-flags: -Znext-solver
|
|
|
|
#![allow(unused_must_use)]
|
|
#![feature(panic_always_abort)]
|
|
// Since we mark some ABIs as "nounwind" to LLVM, we must make sure that
|
|
// we never unwind through them.
|
|
|
|
//@ ignore-wasm32 no processes
|
|
//@ ignore-sgx no processes
|
|
|
|
use std::io;
|
|
use std::io::prelude::*;
|
|
use std::process::{exit, Command, Stdio};
|
|
use std::sync::{Arc, Barrier};
|
|
use std::thread;
|
|
use std::{env, panic};
|
|
|
|
extern "C" fn panic_in_ffi() {
|
|
panic!("Test");
|
|
}
|
|
|
|
fn should_have_aborted() {
|
|
io::stdout().write(b"This should never be printed.\n");
|
|
let _ = io::stdout().flush();
|
|
}
|
|
|
|
fn bomb_out_but_not_abort(msg: &str) {
|
|
eprintln!("bombing out: {}", msg);
|
|
exit(1);
|
|
}
|
|
|
|
fn test() {
|
|
let _ = panic::catch_unwind(|| {
|
|
panic_in_ffi();
|
|
});
|
|
should_have_aborted();
|
|
}
|
|
|
|
fn test_always_abort() {
|
|
panic::always_abort();
|
|
let _ = panic::catch_unwind(|| {
|
|
panic!();
|
|
});
|
|
should_have_aborted();
|
|
}
|
|
|
|
fn test_always_abort_thread() {
|
|
let barrier = Arc::new(Barrier::new(2));
|
|
let thr = {
|
|
let barrier = barrier.clone();
|
|
thread::spawn(move || {
|
|
barrier.wait();
|
|
panic!("in thread");
|
|
})
|
|
};
|
|
panic::always_abort();
|
|
barrier.wait();
|
|
let _ = thr.join();
|
|
bomb_out_but_not_abort("joined - but we were supposed to panic!");
|
|
}
|
|
|
|
fn main() {
|
|
let tests: &[(_, fn())] = &[
|
|
("test", test),
|
|
("test_always_abort", test_always_abort),
|
|
("test_always_abort_thread", test_always_abort_thread),
|
|
];
|
|
|
|
let args: Vec<String> = env::args().collect();
|
|
if args.len() > 1 {
|
|
// This is inside the self-executed command.
|
|
for (a, f) in tests {
|
|
if &args[1] == a {
|
|
return f();
|
|
}
|
|
}
|
|
bomb_out_but_not_abort("bad test");
|
|
}
|
|
|
|
let execute_self_expecting_abort = |arg| {
|
|
let mut p = Command::new(&args[0])
|
|
.stdout(Stdio::piped())
|
|
.stdin(Stdio::piped())
|
|
.arg(arg)
|
|
.spawn()
|
|
.unwrap();
|
|
let status = p.wait().unwrap();
|
|
assert!(!status.success());
|
|
// Any reasonable platform can distinguish a process which
|
|
// called exit(1) from one which panicked.
|
|
assert_ne!(status.code(), Some(1));
|
|
};
|
|
|
|
for (a, _f) in tests {
|
|
execute_self_expecting_abort(a);
|
|
}
|
|
}
|