Skip to content

Commit 2981d77

Browse files
authored
Rollup merge of #109509 - ehuss:overlapping-tests, r=Mark-Simulacrum
compiletest: Don't allow tests with overlapping prefix names Some tests will delete their output directory before starting. The output directory is based on the test names. If one test is the prefix of another test, then when that test starts, it could try to delete the output directory of the other test with the longer path, or otherwise clash with it while the two tests are trying to create/delete/modify the same directory. In practice, this manifested as a random error on macOS where two tests were trying to create/delete/create `rustdoc/primitive` and `rustdoc/primitive/no_std`, which resulted in an EINVAL (InvalidInput) error. This renames some of the offending tests, adds `compiletest-ignore-dir` to prevent compiletest from processing some files, and adds a check to prevent this from happening in the future. Fixes #109397
2 parents d6f2740 + 1692d0c commit 2981d77

File tree

8 files changed

+35
-2
lines changed

8 files changed

+35
-2
lines changed

src/tools/compiletest/src/main.rs

+35-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use build_helper::git::{get_git_modified_files, get_git_untracked_files};
1212
use core::panic;
1313
use getopts::Options;
1414
use lazycell::LazyCell;
15+
use std::collections::BTreeSet;
1516
use std::ffi::OsString;
1617
use std::fs;
1718
use std::io::{self, ErrorKind};
@@ -409,7 +410,9 @@ pub fn run_tests(config: Config) {
409410

410411
let mut tests = Vec::new();
411412
for c in &configs {
412-
make_tests(c, &mut tests);
413+
let mut found_paths = BTreeSet::new();
414+
make_tests(c, &mut tests, &mut found_paths);
415+
check_overlapping_tests(&found_paths);
413416
}
414417

415418
tests.sort_by(|a, b| a.desc.name.as_slice().cmp(&b.desc.name.as_slice()));
@@ -535,7 +538,11 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
535538
}
536539
}
537540

538-
pub fn make_tests(config: &Config, tests: &mut Vec<test::TestDescAndFn>) {
541+
pub fn make_tests(
542+
config: &Config,
543+
tests: &mut Vec<test::TestDescAndFn>,
544+
found_paths: &mut BTreeSet<PathBuf>,
545+
) {
539546
debug!("making tests from {:?}", config.src_base.display());
540547
let inputs = common_inputs_stamp(config);
541548
let modified_tests = modified_tests(config, &config.src_base).unwrap_or_else(|err| {
@@ -547,6 +554,7 @@ pub fn make_tests(config: &Config, tests: &mut Vec<test::TestDescAndFn>) {
547554
&PathBuf::new(),
548555
&inputs,
549556
tests,
557+
found_paths,
550558
&modified_tests,
551559
)
552560
.unwrap_or_else(|_| panic!("Could not read tests from {}", config.src_base.display()));
@@ -617,6 +625,7 @@ fn collect_tests_from_dir(
617625
relative_dir_path: &Path,
618626
inputs: &Stamp,
619627
tests: &mut Vec<test::TestDescAndFn>,
628+
found_paths: &mut BTreeSet<PathBuf>,
620629
modified_tests: &Vec<PathBuf>,
621630
) -> io::Result<()> {
622631
// Ignore directories that contain a file named `compiletest-ignore-dir`.
@@ -650,6 +659,8 @@ fn collect_tests_from_dir(
650659
let file_name = file.file_name();
651660
if is_test(&file_name) && (!config.only_modified || modified_tests.contains(&file_path)) {
652661
debug!("found test file: {:?}", file_path.display());
662+
let rel_test_path = relative_dir_path.join(file_path.file_stem().unwrap());
663+
found_paths.insert(rel_test_path);
653664
let paths =
654665
TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() };
655666

@@ -664,6 +675,7 @@ fn collect_tests_from_dir(
664675
&relative_file_path,
665676
inputs,
666677
tests,
678+
found_paths,
667679
modified_tests,
668680
)?;
669681
}
@@ -1079,3 +1091,24 @@ fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> {
10791091
fn not_a_digit(c: char) -> bool {
10801092
!c.is_digit(10)
10811093
}
1094+
1095+
fn check_overlapping_tests(found_paths: &BTreeSet<PathBuf>) {
1096+
let mut collisions = Vec::new();
1097+
for path in found_paths {
1098+
for ancestor in path.ancestors().skip(1) {
1099+
if found_paths.contains(ancestor) {
1100+
collisions.push((path, ancestor.clone()));
1101+
}
1102+
}
1103+
}
1104+
if !collisions.is_empty() {
1105+
let collisions: String = collisions
1106+
.into_iter()
1107+
.map(|(path, check_parent)| format!("test {path:?} clashes with {check_parent:?}\n"))
1108+
.collect();
1109+
panic!(
1110+
"{collisions}\n\
1111+
Tests cannot have overlapping names. Make sure they use unique prefixes."
1112+
);
1113+
}
1114+
}
File renamed without changes.

tests/ui/modules_and_files_visibility/mod_file_disambig_aux/compiletest-ignore-dir

Whitespace-only changes.

tests/ui/non_modrs_mods_and_inline_mods/x/y/z/compiletest-ignore-dir

Whitespace-only changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)