mirror of
				https://github.com/rust-lang/rust.git
				synced 2025-11-04 06:56:14 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			138 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			138 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
// run-pass
 | 
						|
// ignore-android FIXME #17520
 | 
						|
// ignore-emscripten spawning processes is not supported
 | 
						|
// ignore-openbsd no support for libbacktrace without filename
 | 
						|
// ignore-sgx no processes
 | 
						|
// ignore-msvc see #62897 and `backtrace-debuginfo.rs` test
 | 
						|
// ignore-fuchsia Backtraces not symbolized
 | 
						|
// compile-flags:-g
 | 
						|
// compile-flags:-Cstrip=none
 | 
						|
 | 
						|
use std::env;
 | 
						|
use std::process::{Command, Stdio};
 | 
						|
use std::str;
 | 
						|
 | 
						|
#[inline(never)]
 | 
						|
fn foo() {
 | 
						|
    let _v = vec![1, 2, 3];
 | 
						|
    if env::var_os("IS_TEST").is_some() {
 | 
						|
        panic!()
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#[inline(never)]
 | 
						|
fn double() {
 | 
						|
    struct Double;
 | 
						|
 | 
						|
    impl Drop for Double {
 | 
						|
        fn drop(&mut self) { panic!("twice") }
 | 
						|
    }
 | 
						|
 | 
						|
    let _d = Double;
 | 
						|
 | 
						|
    panic!("once");
 | 
						|
}
 | 
						|
 | 
						|
fn template(me: &str) -> Command {
 | 
						|
    let mut m = Command::new(me);
 | 
						|
    m.env("IS_TEST", "1")
 | 
						|
     .stdout(Stdio::piped())
 | 
						|
     .stderr(Stdio::piped());
 | 
						|
    return m;
 | 
						|
}
 | 
						|
 | 
						|
fn expected(fn_name: &str) -> String {
 | 
						|
    format!(" backtrace::{}", fn_name)
 | 
						|
}
 | 
						|
 | 
						|
#[cfg(not(panic = "abort"))]
 | 
						|
fn contains_verbose_expected(s: &str, fn_name: &str) -> bool {
 | 
						|
    // HACK(eddyb) work around the fact that verbosely demangled stack traces
 | 
						|
    // (from `RUST_BACKTRACE=full`, or, as is the case here, panic-in-panic)
 | 
						|
    // may contain symbols with hashes in them, i.e. `backtrace[...]::`.
 | 
						|
    let prefix = " backtrace";
 | 
						|
    let suffix = &format!("::{}", fn_name);
 | 
						|
    s.match_indices(prefix).any(|(i, _)| {
 | 
						|
        s[i + prefix.len()..]
 | 
						|
            .trim_start_matches('[')
 | 
						|
            .trim_start_matches(char::is_alphanumeric)
 | 
						|
            .trim_start_matches(']')
 | 
						|
            .starts_with(suffix)
 | 
						|
    })
 | 
						|
}
 | 
						|
 | 
						|
fn runtest(me: &str) {
 | 
						|
    // Make sure that the stack trace is printed
 | 
						|
    let p = template(me).arg("fail").env("RUST_BACKTRACE", "1").spawn().unwrap();
 | 
						|
    let out = p.wait_with_output().unwrap();
 | 
						|
    assert!(!out.status.success());
 | 
						|
    let s = str::from_utf8(&out.stderr).unwrap();
 | 
						|
    assert!(s.contains("stack backtrace") && s.contains(&expected("foo")),
 | 
						|
            "bad output: {}", s);
 | 
						|
    assert!(s.contains(" 0:"), "the frame number should start at 0");
 | 
						|
 | 
						|
    // Make sure the stack trace is *not* printed
 | 
						|
    // (Remove RUST_BACKTRACE from our own environment, in case developer
 | 
						|
    // is running `make check` with it on.)
 | 
						|
    let p = template(me).arg("fail").env_remove("RUST_BACKTRACE").spawn().unwrap();
 | 
						|
    let out = p.wait_with_output().unwrap();
 | 
						|
    assert!(!out.status.success());
 | 
						|
    let s = str::from_utf8(&out.stderr).unwrap();
 | 
						|
    assert!(!s.contains("stack backtrace") && !s.contains(&expected("foo")),
 | 
						|
            "bad output2: {}", s);
 | 
						|
 | 
						|
    // Make sure the stack trace is *not* printed
 | 
						|
    // (RUST_BACKTRACE=0 acts as if it were unset from our own environment,
 | 
						|
    // in case developer is running `make check` with it set.)
 | 
						|
    let p = template(me).arg("fail").env("RUST_BACKTRACE","0").spawn().unwrap();
 | 
						|
    let out = p.wait_with_output().unwrap();
 | 
						|
    assert!(!out.status.success());
 | 
						|
    let s = str::from_utf8(&out.stderr).unwrap();
 | 
						|
    assert!(!s.contains("stack backtrace") && !s.contains(" - foo"),
 | 
						|
            "bad output3: {}", s);
 | 
						|
 | 
						|
    #[cfg(not(panic = "abort"))]
 | 
						|
    {
 | 
						|
        // Make sure a stack trace is printed
 | 
						|
        let p = template(me).arg("double-fail").env("RUST_BACKTRACE","0").spawn().unwrap();
 | 
						|
        let out = p.wait_with_output().unwrap();
 | 
						|
        assert!(!out.status.success());
 | 
						|
        let s = str::from_utf8(&out.stderr).unwrap();
 | 
						|
        // loosened the following from double::h to double:: due to
 | 
						|
        // spurious failures on mac, 32bit, optimized
 | 
						|
        assert!(
 | 
						|
            s.contains("stack backtrace") &&
 | 
						|
                s.contains("panic in a destructor during cleanup") &&
 | 
						|
                contains_verbose_expected(s, "double"),
 | 
						|
            "bad output3: {}", s
 | 
						|
        );
 | 
						|
        // Make sure it's only one stack trace.
 | 
						|
        assert_eq!(s.split("stack backtrace").count(), 2);
 | 
						|
 | 
						|
        // Make sure a stack trace isn't printed too many times
 | 
						|
        // even with RUST_BACKTRACE=1. It should be printed twice.
 | 
						|
        let p = template(me).arg("double-fail")
 | 
						|
                                    .env("RUST_BACKTRACE", "1").spawn().unwrap();
 | 
						|
        let out = p.wait_with_output().unwrap();
 | 
						|
        assert!(!out.status.success());
 | 
						|
        let s = str::from_utf8(&out.stderr).unwrap();
 | 
						|
        let mut i = 0;
 | 
						|
        for _ in 0..2 {
 | 
						|
            i += s[i + 10..].find("stack backtrace").unwrap() + 10;
 | 
						|
        }
 | 
						|
        assert!(s[i + 10..].find("stack backtrace").is_none(),
 | 
						|
                "bad output4: {}", s);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
fn main() {
 | 
						|
    let args: Vec<String> = env::args().collect();
 | 
						|
    if args.len() >= 2 && args[1] == "fail" {
 | 
						|
        foo();
 | 
						|
    } else if args.len() >= 2 && args[1] == "double-fail" {
 | 
						|
        double();
 | 
						|
    } else {
 | 
						|
        runtest(&args[0]);
 | 
						|
    }
 | 
						|
}
 |