Skip to content

Commit 96868ac

Browse files
committed
fix panic when rustc tries to reduce intermediate filenames length with multi byte chars
The issue cannot be reproduced with the former testcase of creating external crates because rust refuses to use "external crate 28_找出字符串中第一个匹配项的下标" because it is not a valid indentifier (starts with number, and contain non ascii chars) But still using 28_找出字符串中第一个匹配项的下标.rs as a filename is accepted by previous rustc releases So we consider it valid, and add an integration test for it to catch any regression on other code related to non ascii filenames.
1 parent 7838ce1 commit 96868ac

File tree

3 files changed

+35
-5
lines changed

3 files changed

+35
-5
lines changed

compiler/rustc_session/src/config.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,13 +1211,26 @@ fn maybe_strip_file_name(mut path: PathBuf) -> PathBuf {
12111211
if path.file_name().map_or(0, |name| name.len()) > MAX_FILENAME_LENGTH {
12121212
let filename = path.file_name().unwrap().to_string_lossy();
12131213
let hash_len = 64 / 4; // Hash64 is 64 bits encoded in hex
1214-
let stripped_len = filename.len() - MAX_FILENAME_LENGTH + hash_len;
1214+
let hyphen_len = 1; // the '-' we insert between hash and suffix
1215+
1216+
// number of bytes of suffix we can keep so that "hash-<suffix>" fits
1217+
let allowed_suffix = MAX_FILENAME_LENGTH.saturating_sub(hash_len + hyphen_len);
1218+
1219+
// number of bytes to remove from the start
1220+
let stripped_bytes = filename.len().saturating_sub(allowed_suffix);
1221+
1222+
// Find the next character boundary at or after `stripped_bytes` so slicing is valid.
1223+
let split_at = filename
1224+
.char_indices()
1225+
.find(|(i, _)| *i >= stripped_bytes)
1226+
.map(|(i, _)| i)
1227+
.unwrap_or(filename.len());
12151228

12161229
let mut hasher = StableHasher::new();
1217-
filename[..stripped_len].hash(&mut hasher);
1230+
filename[..split_at].hash(&mut hasher);
12181231
let hash = hasher.finish::<Hash64>();
12191232

1220-
path.set_file_name(format!("{:x}-{}", hash, &filename[stripped_len..]));
1233+
path.set_file_name(format!("{:x}-{}", hash, &filename[split_at..]));
12211234
}
12221235
path
12231236
}

tests/run-make/lto-long-filenames/rmake.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99

1010
//@ ignore-cross-compile
1111

12-
use std::fs;
13-
1412
use run_make_support::{rfs, rustc};
1513

1614
// This test make sure we don't get such following error:
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@ ignore-cross-compile
2+
3+
use run_make_support::{rfs, rustc};
4+
5+
// This test make sure we don't crash when lto creates output files with long names.
6+
// cn characters can be multi-byte and thus trigger the long filename reduction code more easily.
7+
// we need to make sure that the code is properly generating names at char boundaries.
8+
// as reported in issue #147975
9+
fn main() {
10+
let lto_flags = ["-Clto", "-Clto=yes", "-Clto=off", "-Clto=thin", "-Clto=fat"];
11+
for prefix_len in 0..4 {
12+
let prefix: String = std::iter::repeat("_").take(prefix_len).collect();
13+
let main_file = format!("{}28_找出字符串中第一个匹配项的下标.rs", prefix);
14+
rfs::write(&main_file, "fn main() {}\n");
15+
for flag in lto_flags {
16+
rustc().input(&main_file).arg(flag).run();
17+
}
18+
}
19+
}

0 commit comments

Comments
 (0)