| //@ 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); |
| } |
| } |