rust/tests/ui/backtrace.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

138 lines
4.6 KiB
Rust
Raw Normal View History

// run-pass
// ignore-android FIXME #17520
// ignore-emscripten spawning processes is not supported
// ignore-openbsd no support for libbacktrace without filename
2019-04-24 16:26:33 +00:00
// 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
2014-12-05 15:16:53 +00:00
use std::env;
2015-04-10 18:12:43 +00:00
use std::process::{Command, Stdio};
use std::str;
#[inline(never)]
fn foo() {
2015-01-25 21:05:03 +00:00
let _v = vec![1, 2, 3];
if env::var_os("IS_TEST").is_some() {
panic!()
}
}
#[inline(never)]
fn double() {
2015-01-13 23:44:33 +00:00
struct Double;
impl Drop for Double {
fn drop(&mut self) { panic!("twice") }
}
let _d = Double;
panic!("once");
}
2015-04-10 18:12:43 +00:00
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)
})
}
2015-04-10 18:12:43 +00:00
fn runtest(me: &str) {
// Make sure that the stack trace is printed
2015-04-10 18:12:43 +00:00
let p = template(me).arg("fail").env("RUST_BACKTRACE", "1").spawn().unwrap();
let out = p.wait_with_output().unwrap();
assert!(!out.status.success());
2015-04-10 18:12:43 +00:00
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.)
2015-04-10 18:12:43 +00:00
let p = template(me).arg("fail").env_remove("RUST_BACKTRACE").spawn().unwrap();
let out = p.wait_with_output().unwrap();
assert!(!out.status.success());
2015-04-10 18:12:43 +00:00
let s = str::from_utf8(&out.stderr).unwrap();
assert!(!s.contains("stack backtrace") && !s.contains(&expected("foo")),
"bad output2: {}", s);
allow RUST_BACKTRACE=0 to act as if unset /# This is a combination of 16 commits. /# The first commit's message is: allow RUST_BACKTRACE=disabled to act as if unset When RUST_BACKTRACE is set to "disabled" then this acts as if the env. var is unset. /# This is the 2nd commit message: case insensitive "DiSaBLeD" RUST_BACKTRACE value previously it expected a lowercase "disabled" to treat the env. var as unset /# This is the 3rd commit message: RUST_BACKTRACE=0 acts as if unset previously RUST_BACKTRACE=disabled was doing the same thing /# This is the 4th commit message: RUST_BACKTRACE=0|n|no|off acts as if unset previously only RUST_BACKTRACE=0 acted as if RUST_BACKTRACE was unset Now added more options (case-insensitive): 'n','no' and 'off' eg. RUST_BACKTRACE=oFF /# This is the 5th commit message: DRY on the value of 2 DRY=don't repeat yourself Because having to remember to keep the two places of '2' in sync is not ideal, even though this is a simple enough case. /# This is the 6th commit message: Revert "DRY on the value of 2" This reverts commit 95a0479d5cf72a2b2d9d21ec0bed2823ed213fef. Nevermind this DRY on 2, because we already have a RY on 1, besides the code is less readable this way... /# This is the 7th commit message: attempt to document unsetting RUST_BACKTRACE /# This is the 8th commit message: curb allocations when checking for RUST_BACKTRACE this means we don't check for case-insensitivity anymore /# This is the 9th commit message: as decided, RUST_BACKTRACE=0 turns off backtrace /# This is the 10th commit message: RUST_TEST_NOCAPTURE=0 acts as if unset (that is, capture is on) Any other value acts as if nocapture is enabled (that is, capture is off) /# This is the 11th commit message: update other RUST_TEST_NOCAPTURE occurrences apparently only one place needs updating /# This is the 12th commit message: update RUST_BACKTRACE in man page /# This is the 13th commit message: handle an occurrence of RUST_BACKTRACE /# This is the 14th commit message: ensure consistency with new rules for backtrace /# This is the 15th commit message: a more concise comment for RUST_TEST_NOCAPTURE /# This is the 16th commit message: update RUST_TEST_NOCAPTURE in man page
2016-03-28 12:41:55 +00:00
// 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]);
}
}