Skip to content

Commit 52d2f5e

Browse files
authored
Rollup merge of rust-lang#145005 - tardyp:lto_big_filesize, r=bjorn3
strip prefix of temporary file names when it exceeds filesystem name length limit When doing lto, rustc generates filenames that are concatenating many information. In the case of this testcase, it is concatenating crate name and rust file name, plus some hash, and the extension. In some other cases it will concatenate even more information reducing the maximum effective crate name to about 110 chars on linux filesystems where filename max length is 255 This commit is ensuring that the temporary file names are limited in size, while still reasonably ensuring the unicity (with hashing of the stripped part) Fix: rust-lang#49914
2 parents f40db2a + bc14ad3 commit 52d2f5e

File tree

3 files changed

+60
-2
lines changed

3 files changed

+60
-2
lines changed

compiler/rustc_session/src/config.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ use std::{cmp, fmt, fs, iter};
1616

1717
use externs::{ExternOpt, split_extern_opt};
1818
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
19-
use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
19+
use rustc_data_structures::stable_hasher::{StableHasher, StableOrd, ToStableHashKey};
2020
use rustc_errors::emitter::HumanReadableErrorType;
2121
use rustc_errors::{ColorConfig, DiagArgValue, DiagCtxtFlags, IntoDiagArg};
2222
use rustc_feature::UnstableFeatures;
23+
use rustc_hashes::Hash64;
2324
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
2425
use rustc_span::edition::{DEFAULT_EDITION, EDITION_NAME_LIST, Edition, LATEST_STABLE_EDITION};
2526
use rustc_span::source_map::FilePathMapping;
@@ -1195,7 +1196,25 @@ pub struct OutputFilenames {
11951196
pub const RLINK_EXT: &str = "rlink";
11961197
pub const RUST_CGU_EXT: &str = "rcgu";
11971198
pub const DWARF_OBJECT_EXT: &str = "dwo";
1199+
pub const MAX_FILENAME_LENGTH: usize = 143; // ecryptfs limits filenames to 143 bytes see #49914
11981200

1201+
/// Ensure the filename is not too long, as some filesystems have a limit.
1202+
/// If the filename is too long, hash part of it and append the hash to the filename.
1203+
/// This is a workaround for long crate names generating overly long filenames.
1204+
fn maybe_strip_file_name(mut path: PathBuf) -> PathBuf {
1205+
if path.file_name().map_or(0, |name| name.len()) > MAX_FILENAME_LENGTH {
1206+
let filename = path.file_name().unwrap().to_string_lossy();
1207+
let hash_len = 64 / 4; // Hash64 is 64 bits encoded in hex
1208+
let stripped_len = filename.len() - MAX_FILENAME_LENGTH + hash_len;
1209+
1210+
let mut hasher = StableHasher::new();
1211+
filename[..stripped_len].hash(&mut hasher);
1212+
let hash = hasher.finish::<Hash64>();
1213+
1214+
path.set_file_name(format!("{:x}-{}", hash, &filename[stripped_len..]));
1215+
}
1216+
path
1217+
}
11991218
impl OutputFilenames {
12001219
pub fn new(
12011220
out_directory: PathBuf,
@@ -1288,7 +1307,7 @@ impl OutputFilenames {
12881307
}
12891308

12901309
let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
1291-
self.with_directory_and_extension(temps_directory, &extension)
1310+
maybe_strip_file_name(self.with_directory_and_extension(temps_directory, &extension))
12921311
}
12931312

12941313
pub fn temp_path_for_diagnostic(&self, ext: &str) -> PathBuf {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// This file has very long lines, but there is no way to avoid it as we are testing
2+
// long crate names. so:
3+
// ignore-tidy-linelength
4+
5+
extern crate generated_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_crate_name;
6+
7+
fn main() {}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// This file has very long lines, but there is no way to avoid it as we are testing
2+
// long crate names. so:
3+
// ignore-tidy-linelength
4+
5+
// A variant of the smoke test to check that link time optimization
6+
// (LTO) is accepted by the compiler, and that
7+
// passing its various flags still results in successful compilation, even for very long crate names.
8+
// See https://github.com/rust-lang/rust/issues/49914
9+
10+
//@ ignore-cross-compile
11+
12+
use std::fs;
13+
14+
use run_make_support::{rfs, rustc};
15+
16+
// This test make sure we don't get such following error:
17+
// error: could not write output to generated_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_crate_name.generated_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_crate_name.9384edb61bfd127c-cgu.0.rcgu.o: File name too long
18+
// as reported in issue #49914
19+
fn main() {
20+
let lto_flags = ["-Clto", "-Clto=yes", "-Clto=off", "-Clto=thin", "-Clto=fat"];
21+
let aux_file = "generated_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_crate_name.rs";
22+
// The auxiliary file is used to test long crate names.
23+
// The file name is intentionally long to test the handling of long filenames.
24+
// We don't commit it to avoid issues with Windows paths which have known limitations for the full path length.
25+
// Posix usually only have a limit for the length of the file name.
26+
rfs::write(aux_file, "#![crate_type = \"rlib\"]\n");
27+
28+
for flag in lto_flags {
29+
rustc().input(aux_file).arg(flag).run();
30+
rustc().input("main.rs").arg(flag).run();
31+
}
32+
}

0 commit comments

Comments
 (0)