Skip to content

Commit 52a0ca5

Browse files
committed
Auto merge of #9418 - ehuss:always-meta, r=alexcrichton
Always use full metadata hash for -C metadata. This changes it so that cargo always uses the full metadata hash for `-C metadata`. This ensures that even if a unit isn't using `-C extra-filename` that the symbol hashing uses all the fields used in the other cases. This fixes an issue on macOS where a combination of split-debuginfo and incremental caused the same `.o` filenames to be used, which caused corruption in the incremental cache (see issue for details). Fixes #9353.
2 parents d1c0a9d + 256c43c commit 52a0ca5

File tree

4 files changed

+109
-37
lines changed

4 files changed

+109
-37
lines changed

src/cargo/core/compiler/context/compilation_files.rs

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,17 @@ impl fmt::Debug for Metadata {
8080
}
8181
}
8282

83+
/// Information about the metadata hashes used for a `Unit`.
84+
struct MetaInfo {
85+
/// The symbol hash to use.
86+
meta_hash: Metadata,
87+
/// Whether or not the `-C extra-filename` flag is used to generate unique
88+
/// output filenames for this `Unit`.
89+
///
90+
/// If this is `true`, the `meta_hash` is used for the filename.
91+
use_extra_filename: bool,
92+
}
93+
8394
/// Collection of information about the files emitted by the compiler, and the
8495
/// output directory structure.
8596
pub struct CompilationFiles<'a, 'cfg> {
@@ -94,7 +105,7 @@ pub struct CompilationFiles<'a, 'cfg> {
94105
roots: Vec<Unit>,
95106
ws: &'a Workspace<'cfg>,
96107
/// Metadata hash to use for each unit.
97-
metas: HashMap<Unit, Option<Metadata>>,
108+
metas: HashMap<Unit, MetaInfo>,
98109
/// For each Unit, a list all files produced.
99110
outputs: HashMap<Unit, LazyCell<Arc<Vec<OutputFile>>>>,
100111
}
@@ -160,11 +171,14 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
160171
/// Gets the metadata for the given unit.
161172
///
162173
/// See module docs for more details.
163-
///
164-
/// Returns `None` if the unit should not use a metadata hash (like
165-
/// rustdoc, or some dylibs).
166-
pub fn metadata(&self, unit: &Unit) -> Option<Metadata> {
167-
self.metas[unit]
174+
pub fn metadata(&self, unit: &Unit) -> Metadata {
175+
self.metas[unit].meta_hash
176+
}
177+
178+
/// Returns whether or not `-C extra-filename` is used to extend the
179+
/// output filenames to make them unique.
180+
pub fn use_extra_filename(&self, unit: &Unit) -> bool {
181+
self.metas[unit].use_extra_filename
168182
}
169183

170184
/// Gets the short hash based only on the `PackageId`.
@@ -201,9 +215,11 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
201215
/// taken in those cases!
202216
fn pkg_dir(&self, unit: &Unit) -> String {
203217
let name = unit.pkg.package_id().name();
204-
match self.metas[unit] {
205-
Some(ref meta) => format!("{}-{}", name, meta),
206-
None => format!("{}-{}", name, self.target_short_hash(unit)),
218+
let meta = &self.metas[unit];
219+
if meta.use_extra_filename {
220+
format!("{}-{}", name, meta.meta_hash)
221+
} else {
222+
format!("{}-{}", name, self.target_short_hash(unit))
207223
}
208224
}
209225

@@ -448,8 +464,9 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
448464
// Convert FileType to OutputFile.
449465
let mut outputs = Vec::new();
450466
for file_type in file_types {
451-
let meta = self.metadata(unit).map(|m| m.to_string());
452-
let path = out_dir.join(file_type.output_filename(&unit.target, meta.as_deref()));
467+
let meta = &self.metas[unit];
468+
let meta_opt = meta.use_extra_filename.then(|| meta.meta_hash.to_string());
469+
let path = out_dir.join(file_type.output_filename(&unit.target, meta_opt.as_deref()));
453470
let hardlink = self.uplift_to(unit, &file_type, &path);
454471
let export_path = if unit.target.is_custom_build() {
455472
None
@@ -471,30 +488,27 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
471488
}
472489
}
473490

474-
fn metadata_of(
491+
fn metadata_of<'a>(
475492
unit: &Unit,
476493
cx: &Context<'_, '_>,
477-
metas: &mut HashMap<Unit, Option<Metadata>>,
478-
) -> Option<Metadata> {
494+
metas: &'a mut HashMap<Unit, MetaInfo>,
495+
) -> &'a MetaInfo {
479496
if !metas.contains_key(unit) {
480497
let meta = compute_metadata(unit, cx, metas);
481498
metas.insert(unit.clone(), meta);
482499
for dep in cx.unit_deps(unit) {
483500
metadata_of(&dep.unit, cx, metas);
484501
}
485502
}
486-
metas[unit]
503+
&metas[unit]
487504
}
488505

489506
fn compute_metadata(
490507
unit: &Unit,
491508
cx: &Context<'_, '_>,
492-
metas: &mut HashMap<Unit, Option<Metadata>>,
493-
) -> Option<Metadata> {
509+
metas: &mut HashMap<Unit, MetaInfo>,
510+
) -> MetaInfo {
494511
let bcx = &cx.bcx;
495-
if !should_use_metadata(bcx, unit) {
496-
return None;
497-
}
498512
let mut hasher = StableHasher::new();
499513

500514
METADATA_VERSION.hash(&mut hasher);
@@ -514,7 +528,7 @@ fn compute_metadata(
514528
let mut deps_metadata = cx
515529
.unit_deps(unit)
516530
.iter()
517-
.map(|dep| metadata_of(&dep.unit, cx, metas))
531+
.map(|dep| metadata_of(&dep.unit, cx, metas).meta_hash)
518532
.collect::<Vec<_>>();
519533
deps_metadata.sort();
520534
deps_metadata.hash(&mut hasher);
@@ -561,7 +575,10 @@ fn compute_metadata(
561575
// with user dependencies.
562576
unit.is_std.hash(&mut hasher);
563577

564-
Some(Metadata(hasher.finish()))
578+
MetaInfo {
579+
meta_hash: Metadata(hasher.finish()),
580+
use_extra_filename: should_use_metadata(bcx, unit),
581+
}
565582
}
566583

567584
fn hash_rustc_version(bcx: &BuildContext<'_, '_>, hasher: &mut StableHasher) {

src/cargo/core/compiler/context/mod.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -391,9 +391,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
391391
/// Returns the metadata hash for a RunCustomBuild unit.
392392
pub fn get_run_build_script_metadata(&self, unit: &Unit) -> Metadata {
393393
assert!(unit.mode.is_run_custom_build());
394-
self.files()
395-
.metadata(unit)
396-
.expect("build script should always have hash")
394+
self.files().metadata(unit)
397395
}
398396

399397
pub fn is_primary_package(&self, unit: &Unit) -> bool {

src/cargo/core/compiler/mod.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,14 @@ fn rustc(cx: &mut Context<'_, '_>, unit: &Unit, exec: &Arc<dyn Executor>) -> Car
229229
let pass_l_flag = unit.target.is_lib() || !unit.pkg.targets().iter().any(|t| t.is_lib());
230230
let link_type = (&unit.target).into();
231231

232-
let dep_info_name = match cx.files().metadata(unit) {
233-
Some(metadata) => format!("{}-{}.d", unit.target.crate_name(), metadata),
234-
None => format!("{}.d", unit.target.crate_name()),
232+
let dep_info_name = if cx.files().use_extra_filename(unit) {
233+
format!(
234+
"{}-{}.d",
235+
unit.target.crate_name(),
236+
cx.files().metadata(unit)
237+
)
238+
} else {
239+
format!("{}.d", unit.target.crate_name())
235240
};
236241
let rustc_dep_info_loc = root.join(dep_info_name);
237242
let dep_info_loc = fingerprint::dep_info_loc(cx, unit);
@@ -881,15 +886,10 @@ fn build_base_args(
881886
cmd.arg("--cfg").arg(&format!("feature=\"{}\"", feat));
882887
}
883888

884-
match cx.files().metadata(unit) {
885-
Some(m) => {
886-
cmd.arg("-C").arg(&format!("metadata={}", m));
887-
cmd.arg("-C").arg(&format!("extra-filename=-{}", m));
888-
}
889-
None => {
890-
cmd.arg("-C")
891-
.arg(&format!("metadata={}", cx.files().target_short_hash(unit)));
892-
}
889+
let meta = cx.files().metadata(unit);
890+
cmd.arg("-C").arg(&format!("metadata={}", meta));
891+
if cx.files().use_extra_filename(unit) {
892+
cmd.arg("-C").arg(&format!("extra-filename=-{}", meta));
893893
}
894894

895895
if rpath {

tests/testsuite/old_cargos.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,3 +587,60 @@ foo v0.1.0 [..]
587587
)
588588
.run();
589589
}
590+
591+
#[cargo_test]
592+
#[ignore]
593+
fn avoids_split_debuginfo_collision() {
594+
// Checks for a bug where .o files were being incorrectly shared between
595+
// different toolchains using incremental and split-debuginfo on macOS.
596+
let p = project()
597+
.file(
598+
"Cargo.toml",
599+
r#"
600+
[package]
601+
name = "foo"
602+
version = "0.1.0"
603+
604+
[profile.dev]
605+
split-debuginfo = "unpacked"
606+
"#,
607+
)
608+
.file("src/main.rs", "fn main() {}")
609+
.build();
610+
611+
execs()
612+
.with_process_builder(tc_process("cargo", "stable"))
613+
.arg("build")
614+
.env("CARGO_INCREMENTAL", "1")
615+
.cwd(p.root())
616+
.with_stderr(
617+
"\
618+
[COMPILING] foo v0.1.0 [..]
619+
[FINISHED] [..]
620+
",
621+
)
622+
.run();
623+
624+
p.cargo("build")
625+
.env("CARGO_INCREMENTAL", "1")
626+
.with_stderr(
627+
"\
628+
[COMPILING] foo v0.1.0 [..]
629+
[FINISHED] [..]
630+
",
631+
)
632+
.run();
633+
634+
execs()
635+
.with_process_builder(tc_process("cargo", "stable"))
636+
.arg("build")
637+
.env("CARGO_INCREMENTAL", "1")
638+
.cwd(p.root())
639+
.with_stderr(
640+
"\
641+
[COMPILING] foo v0.1.0 [..]
642+
[FINISHED] [..]
643+
",
644+
)
645+
.run();
646+
}

0 commit comments

Comments
 (0)