Skip to content

tests: Require run-fail ui tests to have an exit code (SIGABRT not ok) #143002

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/doc/rustc-dev-guide/src/tests/directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,10 @@ expectations](ui.md#controlling-passfail-expectations).
| `check-fail` | Building (no codegen) should fail | `ui`, `crashes` | N/A |
| `build-pass` | Building should pass | `ui`, `crashes`, `codegen`, `incremental` | N/A |
| `build-fail` | Building should fail | `ui`, `crashes` | N/A |
| `run-pass` | Running the test binary should pass | `ui`, `crashes`, `incremental` | N/A |
| `run-fail` | Running the test binary should fail | `ui`, `crashes` | N/A |
| `run-pass` | Program must exit with code `0` | `ui`, `crashes`, `incremental` | N/A |
| `run-fail` | Program must exit with code `1..=127` | `ui`, `crashes` | N/A |
| `run-crash` | Program must crash | `ui` | N/A |
| `run-fail-or-crash` | Program must `run-fail` or `run-crash` | `ui` | N/A |
| `ignore-pass` | Ignore `--pass` flag | `ui`, `crashes`, `codegen`, `incremental` | N/A |
| `dont-check-failure-status` | Don't check exact failure status (i.e. `1`) | `ui`, `incremental` | N/A |
| `failure-status` | Check | `ui`, `crashes` | Any `u16` |
Expand Down
16 changes: 11 additions & 5 deletions src/doc/rustc-dev-guide/src/tests/ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ even run the resulting program. Just add one of the following
- `//@ build-pass` — compilation and linking should succeed but do
not run the resulting binary.
- `//@ run-pass` — compilation should succeed and running the resulting
binary should also succeed.
binary should make it exit with code 0 which indicates success.
- Fail directives:
- `//@ check-fail` — compilation should fail (the codegen phase is skipped).
This is the default for UI tests.
Expand All @@ -457,10 +457,16 @@ even run the resulting program. Just add one of the following
without the codegen phase, then a second time the full compile should
fail.
- `//@ run-fail` — compilation should succeed, but running the resulting
binary should fail.

For `run-pass` and `run-fail` tests, by default the output of the program itself
is not checked.
binary should make it exit with a code in the range `1..=127` which
indicates regular failure.
- `//@ run-crash` — compilation should succeed, but running the resulting
binary should fail with a crash (e.g. `SIGABRT` or `SIGSEGV`).
- `//@ run-crash-or-crash` — compilation should succeed, but running the
resulting binary should either fail with a code in the range `1..=127` or
crash (e.g. `SIGABRT` or `SIGSEGV`).

For `run-pass`. `run-fail`, `run-crash` and `run-fail-or-crash` tests, by
default the output of the program itself is not checked.

If you want to check the output of running the program, include the
`check-run-results` directive. This will check for a `.run.stderr` and
Expand Down
28 changes: 27 additions & 1 deletion src/tools/compiletest/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,37 @@ string_enum! {
}
}

string_enum! {
#[derive(Clone, Copy, PartialEq, Debug, Hash)]
pub enum RunResult {
Pass => "run-pass",
Fail => "run-fail",
Crash => "run-crash",
}
}

#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub enum RunFailMode {
/// Running the program must make it exit with a regular failure exit code
/// in the range `1..=127`. If the program is terminated by e.g. a signal
/// the test will fail.
Fail,
/// Running the program must result in a crash, e.g. by `SIGABRT` or
/// `SIGSEGV` on Unix or on Windows by having an appropriate NTSTATUS high
/// bit in the exit code.
Crash,
/// Running the program must either fail or crash. Useful for e.g. sanitizer
/// tests since some sanitizer implementations exit the process with code 1
/// to in the face of memory errors while others abort (crash) the process
/// in the face of memory errors.
FailOrCrash,
}

#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub enum FailMode {
Check,
Build,
Run,
Run(RunFailMode),
}

string_enum! {
Expand Down
2 changes: 2 additions & 0 deletions src/tools/compiletest/src/directive-list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,9 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
"regex-error-pattern",
"remap-src-base",
"revisions",
"run-crash",
"run-fail",
"run-fail-or-crash",
"run-flags",
"run-pass",
"run-rustfix",
Expand Down
10 changes: 8 additions & 2 deletions src/tools/compiletest/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use camino::{Utf8Path, Utf8PathBuf};
use semver::Version;
use tracing::*;

use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
use crate::common::{Config, Debugger, FailMode, Mode, PassMode, RunFailMode};
use crate::debuggers::{extract_cdb_version, extract_gdb_version};
use crate::errors::ErrorKind;
use crate::executor::{CollectedTestDesc, ShouldPanic};
Expand Down Expand Up @@ -655,7 +655,13 @@ impl TestProps {
Some(FailMode::Build)
} else if config.parse_name_directive(ln, "run-fail") {
check_ui("run");
Some(FailMode::Run)
Some(FailMode::Run(RunFailMode::Fail))
} else if config.parse_name_directive(ln, "run-crash") {
check_ui("run");
Some(FailMode::Run(RunFailMode::Crash))
} else if config.parse_name_directive(ln, "run-fail-or-crash") {
check_ui("run");
Some(FailMode::Run(RunFailMode::FailOrCrash))
} else {
None
};
Expand Down
28 changes: 23 additions & 5 deletions src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ use tracing::*;

use crate::common::{
Assembly, Codegen, CodegenUnits, CompareMode, Config, CoverageMap, CoverageRun, Crashes,
DebugInfo, Debugger, FailMode, Incremental, MirOpt, PassMode, Pretty, RunMake, Rustdoc,
RustdocJs, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT,
UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path, incremental_dir,
output_base_dir, output_base_name, output_testname_unique,
DebugInfo, Debugger, FailMode, Incremental, MirOpt, PassMode, Pretty, RunFailMode, RunMake,
RunResult, Rustdoc, RustdocJs, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR,
UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path,
incremental_dir, output_base_dir, output_base_name, output_testname_unique,
};
use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff};
use crate::errors::{Error, ErrorKind, load_errors};
Expand Down Expand Up @@ -277,7 +277,11 @@ impl<'test> TestCx<'test> {

fn should_run(&self, pm: Option<PassMode>) -> WillExecute {
let test_should_run = match self.config.mode {
Ui if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) => true,
Ui if pm == Some(PassMode::Run)
|| matches!(self.props.fail_mode, Some(FailMode::Run(_))) =>
{
true
}
MirOpt if pm == Some(PassMode::Run) => true,
Ui | MirOpt => false,
mode => panic!("unimplemented for mode {:?}", mode),
Expand Down Expand Up @@ -2959,6 +2963,20 @@ impl ProcRes {
// compiletest, which is unnecessary noise.
std::panic::resume_unwind(Box::new(()));
}

pub fn run_result_and_code(&self) -> (RunResult, Option<i32>) {
let code = self.status.code();
(
if self.status.success() {
RunResult::Pass
} else if code.is_some_and(|c| c >= 1 && c <= 127) {
RunResult::Fail
} else {
RunResult::Crash
},
code,
)
}
}

#[derive(Debug)]
Expand Down
49 changes: 43 additions & 6 deletions src/tools/compiletest/src/runtest/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use rustfix::{Filter, apply_suggestions, get_suggestions_from_json};
use tracing::debug;

use super::{
AllowUnused, Emit, FailMode, LinkToAux, PassMode, TargetLocation, TestCx, TestOutput,
Truncated, UI_FIXED, WillExecute,
AllowUnused, Emit, FailMode, LinkToAux, PassMode, RunFailMode, RunResult, TargetLocation,
TestCx, TestOutput, Truncated, UI_FIXED, WillExecute,
};
use crate::json;

Expand Down Expand Up @@ -140,12 +140,49 @@ impl TestCx<'_> {
&proc_res,
);
}
let (run_result, code) = proc_res.run_result_and_code();
// Help users understand why the test failed by including the actual
// exit code and actual run result in the failure message.
let pass_hint = format!("code={code:?} (test would pass as `{run_result}`)");
if self.should_run_successfully(pm) {
if !proc_res.status.success() {
self.fatal_proc_rec("test run failed!", &proc_res);
if run_result != RunResult::Pass {
self.fatal_proc_rec(
&format!("test did not exit with success! {pass_hint}"),
&proc_res,
);
}
} else if proc_res.status.success() {
self.fatal_proc_rec("test run succeeded!", &proc_res);
} else if self.props.fail_mode == Some(FailMode::Run(RunFailMode::Fail)) {
// If the test is marked as `run-fail` but do not support
// unwinding we allow it to crash, since a panic will trigger an
// abort (crash) instead of unwind (exit with code 101).
let crash_ok = !self.config.can_unwind();
if run_result != RunResult::Fail && !(crash_ok && run_result == RunResult::Crash) {
let extra_msg = if crash_ok {
&format!(
" or crash (crash allowed since `{}` does not support unwinding)",
self.config.target
)
} else {
""
};
self.fatal_proc_rec(
&format!("test did not exit with failure{extra_msg}! {pass_hint}",),
&proc_res,
);
}
} else if self.props.fail_mode == Some(FailMode::Run(RunFailMode::Crash)) {
if run_result != RunResult::Crash {
self.fatal_proc_rec(&format!("test did not crash! {pass_hint}"), &proc_res);
}
} else if self.props.fail_mode == Some(FailMode::Run(RunFailMode::FailOrCrash)) {
if run_result != RunResult::Fail && run_result != RunResult::Crash {
self.fatal_proc_rec(
&format!("test did not exit with failure or crash! {pass_hint}"),
&proc_res,
);
}
} else {
unreachable!("run_ui_test() must not be called if the test should not run");
}

self.get_output(&proc_res)
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/contracts/contract-attributes-generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
//@ [unchk_pass] run-pass
//@ [chk_pass] run-pass
//
//@ [chk_fail_pre] run-fail
//@ [chk_fail_post] run-fail
//@ [chk_const_fail] run-fail
//@ [chk_fail_pre] run-crash
//@ [chk_fail_post] run-crash
//@ [chk_const_fail] run-crash
//
//@ [unchk_pass] compile-flags: -Zcontract-checks=no
//
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/contracts/contract-attributes-nest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
//@ [unchk_fail_post] run-pass
//@ [chk_pass] run-pass
//
//@ [chk_fail_pre] run-fail
//@ [chk_fail_post] run-fail
//@ [chk_fail_pre] run-crash
//@ [chk_fail_post] run-crash
//
//@ [unchk_pass] compile-flags: -Zcontract-checks=no
//@ [unchk_fail_pre] compile-flags: -Zcontract-checks=no
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/contracts/contract-attributes-tail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
//@ [unchk_fail_post] run-pass
//@ [chk_pass] run-pass
//
//@ [chk_fail_pre] run-fail
//@ [chk_fail_post] run-fail
//@ [chk_fail_pre] run-crash
//@ [chk_fail_post] run-crash
//
//@ [unchk_pass] compile-flags: -Zcontract-checks=no
//@ [unchk_fail_pre] compile-flags: -Zcontract-checks=no
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/contracts/contract-captures-via-closure-copy.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//@ run-fail
//@ run-crash
//@ compile-flags: -Zcontract-checks=yes

#![feature(contracts)]
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/contracts/contract-const-fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
//
//@ [all_pass] run-pass
//
//@ [runtime_fail_pre] run-fail
//@ [runtime_fail_post] run-fail
//@ [runtime_fail_pre] run-crash
//@ [runtime_fail_post] run-crash
//
//@ [all_pass] compile-flags: -Zcontract-checks=yes
//@ [runtime_fail_pre] compile-flags: -Zcontract-checks=yes
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/contracts/contracts-ensures-early-fn-exit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
//
//@ [unchk_pass] run-pass
//@ [chk_pass] run-pass
//@ [chk_fail_try] run-fail
//@ [chk_fail_ret] run-fail
//@ [chk_fail_yeet] run-fail
//@ [chk_fail_try] run-crash
//@ [chk_fail_ret] run-crash
//@ [chk_fail_yeet] run-crash
//
//@ [unchk_pass] compile-flags: -Zcontract-checks=no
//@ [chk_pass] compile-flags: -Zcontract-checks=yes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
//@ [unchk_fail_post] run-pass
//@ [chk_pass] run-pass
//
//@ [chk_fail_pre] run-fail
//@ [chk_fail_post] run-fail
//@ [chk_fail_pre] run-crash
//@ [chk_fail_post] run-crash
//
//@ [unchk_pass] compile-flags: -Zcontract-checks=no
//@ [unchk_fail_pre] compile-flags: -Zcontract-checks=no
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
//@ [unchk_fail_post] run-pass
//@ [chk_pass] run-pass
//
//@ [chk_fail_pre] run-fail
//@ [chk_fail_post] run-fail
//@ [chk_fail_pre] run-crash
//@ [chk_fail_post] run-crash
//
//@ [unchk_pass] compile-flags: -Zcontract-checks=no
//@ [unchk_fail_pre] compile-flags: -Zcontract-checks=no
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/contracts/internal_machinery/contract-intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
//@ [default] run-pass
//@ [unchk_pass] run-pass
//@ [chk_pass] run-pass
//@ [chk_fail_requires] run-fail
//@ [chk_fail_ensures] run-fail
//@ [chk_fail_requires] run-crash
//@ [chk_fail_ensures] run-crash
//
//@ [unchk_pass] compile-flags: -Zcontract-checks=no
//@ [chk_pass] compile-flags: -Zcontract-checks=yes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//@ [unchk_fail_post] run-pass
//@ [chk_pass] run-pass
//
//@ [chk_fail_post] run-fail
//@ [chk_fail_post] run-crash
//
//@ [unchk_pass] compile-flags: -Zcontract-checks=no
//@ [unchk_fail_post] compile-flags: -Zcontract-checks=no
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/extern/extern-types-field-offset.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//@ run-fail
//@ run-crash
//@ check-run-results
//@ exec-env:RUST_BACKTRACE=0
//@ normalize-stderr: "(core/src/panicking\.rs):[0-9]+:[0-9]+" -> "$1:$$LINE:$$COL"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//@ run-fail
//@ run-crash
//@ ignore-i686-pc-windows-msvc: #112480
//@ compile-flags: -C debug-assertions
//@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/mir/alignment/misaligned_borrow.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//@ run-fail
//@ run-crash
//@ ignore-i686-pc-windows-msvc: #112480
//@ compile-flags: -C debug-assertions
//@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/mir/alignment/misaligned_lhs.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//@ run-fail
//@ run-crash
//@ ignore-i686-pc-windows-msvc: #112480
//@ compile-flags: -C debug-assertions
//@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/mir/alignment/misaligned_mut_borrow.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//@ run-fail
//@ run-crash
//@ ignore-i686-pc-windows-msvc: #112480
//@ compile-flags: -C debug-assertions
//@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/mir/alignment/misaligned_rhs.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//@ run-fail
//@ run-crash
//@ ignore-i686-pc-windows-msvc: #112480
//@ compile-flags: -C debug-assertions
//@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/mir/alignment/two_pointers.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//@ run-fail
//@ run-crash
//@ ignore-i686-pc-windows-msvc: #112480
//@ compile-flags: -C debug-assertions
//@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/mir/enum/convert_non_enum_break.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//@ run-fail
//@ run-crash
//@ compile-flags: -C debug-assertions
//@ error-pattern: trying to construct an enum from an invalid value 0x10000

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/mir/enum/convert_non_enum_niche_break.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//@ run-fail
//@ run-crash
//@ compile-flags: -C debug-assertions
//@ error-pattern: trying to construct an enum from an invalid value 0x5

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/mir/enum/niche_option_tuple_break.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//@ run-fail
//@ run-crash
//@ compile-flags: -C debug-assertions
//@ error-pattern: trying to construct an enum from an invalid value 0x3

Expand Down
Loading
Loading