Skip to content

Commit 6950daf

Browse files
committed
tests: Require run-fail ui tests to have an exit code (SIGABRT not ok)
And introduce two new directives for ui tests: * `run-crash` * `run-fail-or-crash` Normally a `run-fail` ui test like tests that panic shall not be terminated by a signal like `SIGABRT`. So begin having that as a hard requirement. Some of our current tests do terminate by a signal/crash however. Introduce and use `run-crash` for those tests. Note that Windows crashes are not handled by signals but by certain high bits set on the process exit code. Example exit code for crash on Windows: `0xc000001d`. Because of this, we define "crash" on all platforms as "not exit with success and not exit with a regular failure code in the range 1..=127". Some tests behave differently on different targets: * Targets without unwind support will abort (crash) instead of exit with failure code 101 after panicking. As a special case, allow crashes for `run-fail` tests for such targets. * Different sanitizer implementations handle detected memory problems differently. Some abort (crash) the process while others exit with failure code 1. Introduce and use `run-fail-or-crash` for such tests.
1 parent 6268d0a commit 6950daf

File tree

75 files changed

+190
-99
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+190
-99
lines changed

src/doc/rustc-dev-guide/src/tests/directives.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,10 @@ expectations](ui.md#controlling-passfail-expectations).
7575
| `check-fail` | Building (no codegen) should fail | `ui`, `crashes` | N/A |
7676
| `build-pass` | Building should pass | `ui`, `crashes`, `codegen`, `incremental` | N/A |
7777
| `build-fail` | Building should fail | `ui`, `crashes` | N/A |
78-
| `run-pass` | Running the test binary should pass | `ui`, `crashes`, `incremental` | N/A |
79-
| `run-fail` | Running the test binary should fail | `ui`, `crashes` | N/A |
78+
| `run-pass` | Program must exit with code `0` | `ui`, `crashes`, `incremental` | N/A |
79+
| `run-fail` | Program must exit with code `1..=127` | `ui`, `crashes` | N/A |
80+
| `run-crash` | Program must crash | `ui` | N/A |
81+
| `run-fail-or-crash` | Program must `run-fail` or `run-crash` | `ui` | N/A |
8082
| `ignore-pass` | Ignore `--pass` flag | `ui`, `crashes`, `codegen`, `incremental` | N/A |
8183
| `dont-check-failure-status` | Don't check exact failure status (i.e. `1`) | `ui`, `incremental` | N/A |
8284
| `failure-status` | Check | `ui`, `crashes` | Any `u16` |

src/doc/rustc-dev-guide/src/tests/ui.md

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ even run the resulting program. Just add one of the following
448448
- `//@ build-pass` — compilation and linking should succeed but do
449449
not run the resulting binary.
450450
- `//@ run-pass` — compilation should succeed and running the resulting
451-
binary should also succeed.
451+
binary should make it exit with code 0 which indicates success.
452452
- Fail directives:
453453
- `//@ check-fail` — compilation should fail (the codegen phase is skipped).
454454
This is the default for UI tests.
@@ -457,10 +457,20 @@ even run the resulting program. Just add one of the following
457457
without the codegen phase, then a second time the full compile should
458458
fail.
459459
- `//@ run-fail` — compilation should succeed, but running the resulting
460-
binary should fail.
461-
462-
For `run-pass` and `run-fail` tests, by default the output of the program itself
463-
is not checked.
460+
binary should make it exit with a code in the range `1..=127` which
461+
indicates regular failure. On targets without unwind support, crashes
462+
are also accepted.
463+
- `//@ run-crash` — compilation should succeed, but running the resulting
464+
binary should fail with a crash. Crashing is defined as "not exiting with
465+
a code in the range `0..=127`". Example on Linux: Termination by `SIGABRT`
466+
or `SIGSEGV`. Example on Windows: Exiting with the code for
467+
`STATUS_ILLEGAL_INSTRUCTION` (`0xC000001D`).
468+
- `//@ run-fail-or-crash` — compilation should succeed, but running the
469+
resulting binary should either `run-fail` or `run-crash`. Useful if a test
470+
crashes on some targets but just fails on others.
471+
472+
For `run-pass`. `run-fail`, `run-crash` and `run-fail-or-crash` tests, by
473+
default the output of the program itself is not checked.
464474

465475
If you want to check the output of running the program, include the
466476
`check-run-results` directive. This will check for a `.run.stderr` and

src/tools/compiletest/src/common.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,37 @@ string_enum! {
111111
}
112112
}
113113

114+
string_enum! {
115+
#[derive(Clone, Copy, PartialEq, Debug, Hash)]
116+
pub enum RunResult {
117+
Pass => "run-pass",
118+
Fail => "run-fail",
119+
Crash => "run-crash",
120+
}
121+
}
122+
123+
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
124+
pub enum RunFailMode {
125+
/// Running the program must make it exit with a regular failure exit code
126+
/// in the range `1..=127`. If the program is terminated by e.g. a signal
127+
/// the test will fail.
128+
Fail,
129+
/// Running the program must result in a crash, e.g. by `SIGABRT` or
130+
/// `SIGSEGV` on Unix or on Windows by having an appropriate NTSTATUS high
131+
/// bit in the exit code.
132+
Crash,
133+
/// Running the program must either fail or crash. Useful for e.g. sanitizer
134+
/// tests since some sanitizer implementations exit the process with code 1
135+
/// to in the face of memory errors while others abort (crash) the process
136+
/// in the face of memory errors.
137+
FailOrCrash,
138+
}
139+
114140
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
115141
pub enum FailMode {
116142
Check,
117143
Build,
118-
Run,
144+
Run(RunFailMode),
119145
}
120146

121147
string_enum! {

src/tools/compiletest/src/directive-list.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,9 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
241241
"regex-error-pattern",
242242
"remap-src-base",
243243
"revisions",
244+
"run-crash",
244245
"run-fail",
246+
"run-fail-or-crash",
245247
"run-flags",
246248
"run-pass",
247249
"run-rustfix",

src/tools/compiletest/src/directives.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use camino::{Utf8Path, Utf8PathBuf};
99
use semver::Version;
1010
use tracing::*;
1111

12-
use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
12+
use crate::common::{Config, Debugger, FailMode, Mode, PassMode, RunFailMode};
1313
use crate::debuggers::{extract_cdb_version, extract_gdb_version};
1414
use crate::directives::auxiliary::{AuxProps, parse_and_update_aux};
1515
use crate::directives::needs::CachedNeedsConditions;
@@ -656,7 +656,13 @@ impl TestProps {
656656
Some(FailMode::Build)
657657
} else if config.parse_name_directive(ln, "run-fail") {
658658
check_ui("run");
659-
Some(FailMode::Run)
659+
Some(FailMode::Run(RunFailMode::Fail))
660+
} else if config.parse_name_directive(ln, "run-crash") {
661+
check_ui("run");
662+
Some(FailMode::Run(RunFailMode::Crash))
663+
} else if config.parse_name_directive(ln, "run-fail-or-crash") {
664+
check_ui("run");
665+
Some(FailMode::Run(RunFailMode::FailOrCrash))
660666
} else {
661667
None
662668
};

src/tools/compiletest/src/runtest.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ use tracing::*;
1717

1818
use crate::common::{
1919
Assembly, Codegen, CodegenUnits, CompareMode, Config, CoverageMap, CoverageRun, Crashes,
20-
DebugInfo, Debugger, FailMode, Incremental, MirOpt, PassMode, Pretty, RunMake, Rustdoc,
21-
RustdocJs, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT,
22-
UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path, incremental_dir,
23-
output_base_dir, output_base_name, output_testname_unique,
20+
DebugInfo, Debugger, FailMode, Incremental, MirOpt, PassMode, Pretty, RunFailMode, RunMake,
21+
RunResult, Rustdoc, RustdocJs, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR,
22+
UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path,
23+
incremental_dir, output_base_dir, output_base_name, output_testname_unique,
2424
};
2525
use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff};
2626
use crate::directives::TestProps;
@@ -277,7 +277,11 @@ impl<'test> TestCx<'test> {
277277

278278
fn should_run(&self, pm: Option<PassMode>) -> WillExecute {
279279
let test_should_run = match self.config.mode {
280-
Ui if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) => true,
280+
Ui if pm == Some(PassMode::Run)
281+
|| matches!(self.props.fail_mode, Some(FailMode::Run(_))) =>
282+
{
283+
true
284+
}
281285
MirOpt if pm == Some(PassMode::Run) => true,
282286
Ui | MirOpt => false,
283287
mode => panic!("unimplemented for mode {:?}", mode),

src/tools/compiletest/src/runtest/ui.rs

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use rustfix::{Filter, apply_suggestions, get_suggestions_from_json};
66
use tracing::debug;
77

88
use super::{
9-
AllowUnused, Emit, FailMode, LinkToAux, PassMode, TargetLocation, TestCx, TestOutput,
10-
Truncated, UI_FIXED, WillExecute,
9+
AllowUnused, Emit, FailMode, LinkToAux, PassMode, RunFailMode, RunResult, TargetLocation,
10+
TestCx, TestOutput, Truncated, UI_FIXED, WillExecute,
1111
};
1212
use crate::json;
1313

@@ -140,12 +140,53 @@ impl TestCx<'_> {
140140
&proc_res,
141141
);
142142
}
143+
let code = proc_res.status.code();
144+
let run_result = if proc_res.status.success() {
145+
RunResult::Pass
146+
} else if code.is_some_and(|c| c >= 1 && c <= 127) {
147+
RunResult::Fail
148+
} else {
149+
RunResult::Crash
150+
};
151+
// Help users understand why the test failed by including the actual
152+
// exit code and actual run result in the failure message.
153+
let pass_hint = format!("code={code:?} so test would pass with `{run_result}`");
143154
if self.should_run_successfully(pm) {
144-
if !proc_res.status.success() {
145-
self.fatal_proc_rec("test run failed!", &proc_res);
155+
if run_result != RunResult::Pass {
156+
self.fatal_proc_rec(
157+
&format!("test did not exit with success! {pass_hint}"),
158+
&proc_res,
159+
);
160+
}
161+
} else if self.props.fail_mode == Some(FailMode::Run(RunFailMode::Fail)) {
162+
// If the test is marked as `run-fail` but do not support
163+
// unwinding we allow it to crash, since a panic will trigger an
164+
// abort (crash) instead of unwind (exit with code 101).
165+
let crash_ok = !self.config.can_unwind();
166+
if run_result != RunResult::Fail && !(crash_ok && run_result == RunResult::Crash) {
167+
let err = if crash_ok {
168+
format!(
169+
"test did not exit with failure or crash (`{}` can't unwind)! {pass_hint}",
170+
self.config.target
171+
)
172+
} else {
173+
format!("test did not exit with failure! {pass_hint}")
174+
};
175+
self.fatal_proc_rec(&err, &proc_res);
146176
}
147-
} else if proc_res.status.success() {
148-
self.fatal_proc_rec("test run succeeded!", &proc_res);
177+
} else if self.props.fail_mode == Some(FailMode::Run(RunFailMode::Crash)) {
178+
if run_result != RunResult::Crash {
179+
self.fatal_proc_rec(&format!("test did not crash! {pass_hint}"), &proc_res);
180+
}
181+
} else if self.props.fail_mode == Some(FailMode::Run(RunFailMode::FailOrCrash)) {
182+
if run_result != RunResult::Fail && run_result != RunResult::Crash {
183+
self.fatal_proc_rec(
184+
&format!("test did not exit with failure or crash! {pass_hint}"),
185+
&proc_res,
186+
);
187+
}
188+
} else {
189+
unreachable!("run_ui_test() must not be called if the test should not run");
149190
}
150191

151192
self.get_output(&proc_res)

tests/ui/contracts/contract-attributes-generics.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
//@ [unchk_pass] run-pass
66
//@ [chk_pass] run-pass
77
//
8-
//@ [chk_fail_pre] run-fail
9-
//@ [chk_fail_post] run-fail
10-
//@ [chk_const_fail] run-fail
8+
//@ [chk_fail_pre] run-crash
9+
//@ [chk_fail_post] run-crash
10+
//@ [chk_const_fail] run-crash
1111
//
1212
//@ [unchk_pass] compile-flags: -Zcontract-checks=no
1313
//

tests/ui/contracts/contract-attributes-nest.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
//@ [unchk_fail_post] run-pass
66
//@ [chk_pass] run-pass
77
//
8-
//@ [chk_fail_pre] run-fail
9-
//@ [chk_fail_post] run-fail
8+
//@ [chk_fail_pre] run-crash
9+
//@ [chk_fail_post] run-crash
1010
//
1111
//@ [unchk_pass] compile-flags: -Zcontract-checks=no
1212
//@ [unchk_fail_pre] compile-flags: -Zcontract-checks=no

tests/ui/contracts/contract-attributes-tail.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
//@ [unchk_fail_post] run-pass
66
//@ [chk_pass] run-pass
77
//
8-
//@ [chk_fail_pre] run-fail
9-
//@ [chk_fail_post] run-fail
8+
//@ [chk_fail_pre] run-crash
9+
//@ [chk_fail_post] run-crash
1010
//
1111
//@ [unchk_pass] compile-flags: -Zcontract-checks=no
1212
//@ [unchk_fail_pre] compile-flags: -Zcontract-checks=no

tests/ui/contracts/contract-captures-via-closure-copy.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ run-fail
1+
//@ run-crash
22
//@ compile-flags: -Zcontract-checks=yes
33

44
#![feature(contracts)]

tests/ui/contracts/contract-const-fn.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
//
99
//@ [all_pass] run-pass
1010
//
11-
//@ [runtime_fail_pre] run-fail
12-
//@ [runtime_fail_post] run-fail
11+
//@ [runtime_fail_pre] run-crash
12+
//@ [runtime_fail_post] run-crash
1313
//
1414
//@ [all_pass] compile-flags: -Zcontract-checks=yes
1515
//@ [runtime_fail_pre] compile-flags: -Zcontract-checks=yes

tests/ui/contracts/contracts-ensures-early-fn-exit.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
//
33
//@ [unchk_pass] run-pass
44
//@ [chk_pass] run-pass
5-
//@ [chk_fail_try] run-fail
6-
//@ [chk_fail_ret] run-fail
7-
//@ [chk_fail_yeet] run-fail
5+
//@ [chk_fail_try] run-crash
6+
//@ [chk_fail_ret] run-crash
7+
//@ [chk_fail_yeet] run-crash
88
//
99
//@ [unchk_pass] compile-flags: -Zcontract-checks=no
1010
//@ [chk_pass] compile-flags: -Zcontract-checks=yes

tests/ui/contracts/internal_machinery/contract-ast-extensions-nest.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
//@ [unchk_fail_post] run-pass
66
//@ [chk_pass] run-pass
77
//
8-
//@ [chk_fail_pre] run-fail
9-
//@ [chk_fail_post] run-fail
8+
//@ [chk_fail_pre] run-crash
9+
//@ [chk_fail_post] run-crash
1010
//
1111
//@ [unchk_pass] compile-flags: -Zcontract-checks=no
1212
//@ [unchk_fail_pre] compile-flags: -Zcontract-checks=no

tests/ui/contracts/internal_machinery/contract-ast-extensions-tail.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
//@ [unchk_fail_post] run-pass
66
//@ [chk_pass] run-pass
77
//
8-
//@ [chk_fail_pre] run-fail
9-
//@ [chk_fail_post] run-fail
8+
//@ [chk_fail_pre] run-crash
9+
//@ [chk_fail_post] run-crash
1010
//
1111
//@ [unchk_pass] compile-flags: -Zcontract-checks=no
1212
//@ [unchk_fail_pre] compile-flags: -Zcontract-checks=no

tests/ui/contracts/internal_machinery/contract-intrinsics.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
//@ [default] run-pass
44
//@ [unchk_pass] run-pass
55
//@ [chk_pass] run-pass
6-
//@ [chk_fail_requires] run-fail
7-
//@ [chk_fail_ensures] run-fail
6+
//@ [chk_fail_requires] run-crash
7+
//@ [chk_fail_ensures] run-crash
88
//
99
//@ [unchk_pass] compile-flags: -Zcontract-checks=no
1010
//@ [chk_pass] compile-flags: -Zcontract-checks=yes

tests/ui/contracts/internal_machinery/contract-lang-items.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//@ [unchk_fail_post] run-pass
55
//@ [chk_pass] run-pass
66
//
7-
//@ [chk_fail_post] run-fail
7+
//@ [chk_fail_post] run-crash
88
//
99
//@ [unchk_pass] compile-flags: -Zcontract-checks=no
1010
//@ [unchk_fail_post] compile-flags: -Zcontract-checks=no

tests/ui/extern/extern-types-field-offset.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ run-fail
1+
//@ run-crash
22
//@ check-run-results
33
//@ exec-env:RUST_BACKTRACE=0
44
//@ normalize-stderr: "(core/src/panicking\.rs):[0-9]+:[0-9]+" -> "$1:$$LINE:$$COL"

tests/ui/mir/alignment/borrow_misaligned_field_projection.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ run-fail
1+
//@ run-crash
22
//@ ignore-i686-pc-windows-msvc: #112480
33
//@ compile-flags: -C debug-assertions
44
//@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is

tests/ui/mir/alignment/misaligned_borrow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ run-fail
1+
//@ run-crash
22
//@ ignore-i686-pc-windows-msvc: #112480
33
//@ compile-flags: -C debug-assertions
44
//@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is

tests/ui/mir/alignment/misaligned_lhs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ run-fail
1+
//@ run-crash
22
//@ ignore-i686-pc-windows-msvc: #112480
33
//@ compile-flags: -C debug-assertions
44
//@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is

tests/ui/mir/alignment/misaligned_mut_borrow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ run-fail
1+
//@ run-crash
22
//@ ignore-i686-pc-windows-msvc: #112480
33
//@ compile-flags: -C debug-assertions
44
//@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is

tests/ui/mir/alignment/misaligned_rhs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ run-fail
1+
//@ run-crash
22
//@ ignore-i686-pc-windows-msvc: #112480
33
//@ compile-flags: -C debug-assertions
44
//@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is

tests/ui/mir/alignment/two_pointers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ run-fail
1+
//@ run-crash
22
//@ ignore-i686-pc-windows-msvc: #112480
33
//@ compile-flags: -C debug-assertions
44
//@ error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is

tests/ui/mir/enum/convert_non_enum_break.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ run-fail
1+
//@ run-crash
22
//@ compile-flags: -C debug-assertions
33
//@ error-pattern: trying to construct an enum from an invalid value 0x10000
44

tests/ui/mir/enum/convert_non_enum_niche_break.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ run-fail
1+
//@ run-crash
22
//@ compile-flags: -C debug-assertions
33
//@ error-pattern: trying to construct an enum from an invalid value 0x5
44

tests/ui/mir/enum/negative_discr_break.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ run-fail
1+
//@ run-crash
22
//@ compile-flags: -C debug-assertions
33
//@ error-pattern: trying to construct an enum from an invalid value 0xfd
44

tests/ui/mir/enum/niche_option_tuple_break.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ run-fail
1+
//@ run-crash
22
//@ compile-flags: -C debug-assertions
33
//@ error-pattern: trying to construct an enum from an invalid value 0x3
44

tests/ui/mir/enum/numbered_variants_break.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ run-fail
1+
//@ run-crash
22
//@ compile-flags: -C debug-assertions
33
//@ error-pattern: trying to construct an enum from an invalid value 0x3
44

0 commit comments

Comments
 (0)