Skip to content

Commit 572cf4a

Browse files
authored
Rollup merge of rust-lang#122187 - bjorn3:merge_header_version_checks, r=petrochenkov
Move metadata header and version checks together This will make it easier to report rustc versions for older metadata formats. Split out of rust-lang#120855
2 parents be4523b + fdff4d7 commit 572cf4a

File tree

3 files changed

+79
-45
lines changed

3 files changed

+79
-45
lines changed

compiler/rustc_driver_impl/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,7 @@ fn list_metadata(early_dcx: &EarlyDiagCtxt, sess: &Session, metadata_loader: &dy
676676
metadata_loader,
677677
&mut v,
678678
&sess.opts.unstable_opts.ls,
679+
sess.cfg_version,
679680
)
680681
.unwrap();
681682
safe_println!("{}", String::from_utf8(v).unwrap());

compiler/rustc_metadata/src/locator.rs

+60-39
Original file line numberDiff line numberDiff line change
@@ -567,31 +567,47 @@ impl<'a> CrateLocator<'a> {
567567
debug!("skipping empty file");
568568
continue;
569569
}
570-
let (hash, metadata) =
571-
match get_metadata_section(self.target, flavor, &lib, self.metadata_loader) {
572-
Ok(blob) => {
573-
if let Some(h) = self.crate_matches(&blob, &lib) {
574-
(h, blob)
575-
} else {
576-
info!("metadata mismatch");
577-
continue;
578-
}
579-
}
580-
Err(MetadataError::LoadFailure(err)) => {
581-
info!("no metadata found: {}", err);
582-
// The file was present and created by the same compiler version, but we
583-
// couldn't load it for some reason. Give a hard error instead of silently
584-
// ignoring it, but only if we would have given an error anyway.
585-
self.crate_rejections
586-
.via_invalid
587-
.push(CrateMismatch { path: lib, got: err });
588-
continue;
589-
}
590-
Err(err @ MetadataError::NotPresent(_)) => {
591-
info!("no metadata found: {}", err);
570+
let (hash, metadata) = match get_metadata_section(
571+
self.target,
572+
flavor,
573+
&lib,
574+
self.metadata_loader,
575+
self.cfg_version,
576+
) {
577+
Ok(blob) => {
578+
if let Some(h) = self.crate_matches(&blob, &lib) {
579+
(h, blob)
580+
} else {
581+
info!("metadata mismatch");
592582
continue;
593583
}
594-
};
584+
}
585+
Err(MetadataError::VersionMismatch { expected_version, found_version }) => {
586+
// The file was present and created by the same compiler version, but we
587+
// couldn't load it for some reason. Give a hard error instead of silently
588+
// ignoring it, but only if we would have given an error anyway.
589+
info!(
590+
"Rejecting via version: expected {} got {}",
591+
expected_version, found_version
592+
);
593+
self.crate_rejections
594+
.via_version
595+
.push(CrateMismatch { path: lib, got: found_version });
596+
continue;
597+
}
598+
Err(MetadataError::LoadFailure(err)) => {
599+
info!("no metadata found: {}", err);
600+
// The file was present and created by the same compiler version, but we
601+
// couldn't load it for some reason. Give a hard error instead of silently
602+
// ignoring it, but only if we would have given an error anyway.
603+
self.crate_rejections.via_invalid.push(CrateMismatch { path: lib, got: err });
604+
continue;
605+
}
606+
Err(err @ MetadataError::NotPresent(_)) => {
607+
info!("no metadata found: {}", err);
608+
continue;
609+
}
610+
};
595611
// If we see multiple hashes, emit an error about duplicate candidates.
596612
if slot.as_ref().is_some_and(|s| s.0 != hash) {
597613
if let Some(candidates) = err_data {
@@ -620,16 +636,6 @@ impl<'a> CrateLocator<'a> {
620636
}
621637

622638
fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> {
623-
let rustc_version = rustc_version(self.cfg_version);
624-
let found_version = metadata.get_rustc_version();
625-
if found_version != rustc_version {
626-
info!("Rejecting via version: expected {} got {}", rustc_version, found_version);
627-
self.crate_rejections
628-
.via_version
629-
.push(CrateMismatch { path: libpath.to_path_buf(), got: found_version });
630-
return None;
631-
}
632-
633639
let header = metadata.get_header();
634640
if header.is_proc_macro_crate != self.is_proc_macro {
635641
info!(
@@ -742,6 +748,7 @@ fn get_metadata_section<'p>(
742748
flavor: CrateFlavor,
743749
filename: &'p Path,
744750
loader: &dyn MetadataLoader,
751+
cfg_version: &'static str,
745752
) -> Result<MetadataBlob, MetadataError<'p>> {
746753
if !filename.exists() {
747754
return Err(MetadataError::NotPresent(filename));
@@ -819,13 +826,18 @@ fn get_metadata_section<'p>(
819826
}
820827
};
821828
let blob = MetadataBlob(raw_bytes);
822-
if blob.is_compatible() {
823-
Ok(blob)
824-
} else {
825-
Err(MetadataError::LoadFailure(format!(
829+
match blob.check_compatibility(cfg_version) {
830+
Ok(()) => Ok(blob),
831+
Err(None) => Err(MetadataError::LoadFailure(format!(
826832
"invalid metadata version found: {}",
827833
filename.display()
828-
)))
834+
))),
835+
Err(Some(found_version)) => {
836+
return Err(MetadataError::VersionMismatch {
837+
expected_version: rustc_version(cfg_version),
838+
found_version,
839+
});
840+
}
829841
}
830842
}
831843

@@ -836,9 +848,10 @@ pub fn list_file_metadata(
836848
metadata_loader: &dyn MetadataLoader,
837849
out: &mut dyn Write,
838850
ls_kinds: &[String],
851+
cfg_version: &'static str,
839852
) -> IoResult<()> {
840853
let flavor = get_flavor_from_path(path);
841-
match get_metadata_section(target, flavor, path, metadata_loader) {
854+
match get_metadata_section(target, flavor, path, metadata_loader, cfg_version) {
842855
Ok(metadata) => metadata.list_crate_metadata(out, ls_kinds),
843856
Err(msg) => write!(out, "{msg}\n"),
844857
}
@@ -904,6 +917,8 @@ enum MetadataError<'a> {
904917
NotPresent(&'a Path),
905918
/// The file was present and invalid.
906919
LoadFailure(String),
920+
/// The file was present, but compiled with a different rustc version.
921+
VersionMismatch { expected_version: String, found_version: String },
907922
}
908923

909924
impl fmt::Display for MetadataError<'_> {
@@ -913,6 +928,12 @@ impl fmt::Display for MetadataError<'_> {
913928
f.write_str(&format!("no such file: '{}'", filename.display()))
914929
}
915930
MetadataError::LoadFailure(msg) => f.write_str(msg),
931+
MetadataError::VersionMismatch { expected_version, found_version } => {
932+
f.write_str(&format!(
933+
"rustc version mismatch. expected {}, found {}",
934+
expected_version, found_version,
935+
))
936+
}
916937
}
917938
}
918939
}

compiler/rustc_metadata/src/rmeta/decoder.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -684,13 +684,25 @@ impl<'a, 'tcx, I: Idx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyTable<I, T>
684684
implement_ty_decoder!(DecodeContext<'a, 'tcx>);
685685

686686
impl MetadataBlob {
687-
pub(crate) fn is_compatible(&self) -> bool {
688-
self.blob().starts_with(METADATA_HEADER)
689-
}
687+
pub(crate) fn check_compatibility(
688+
&self,
689+
cfg_version: &'static str,
690+
) -> Result<(), Option<String>> {
691+
if !self.blob().starts_with(METADATA_HEADER) {
692+
if self.blob().starts_with(b"rust") {
693+
return Err(Some("<unknown rustc version>".to_owned()));
694+
}
695+
return Err(None);
696+
}
690697

691-
pub(crate) fn get_rustc_version(&self) -> String {
692-
LazyValue::<String>::from_position(NonZero::new(METADATA_HEADER.len() + 8).unwrap())
693-
.decode(self)
698+
let found_version =
699+
LazyValue::<String>::from_position(NonZero::new(METADATA_HEADER.len() + 8).unwrap())
700+
.decode(self);
701+
if rustc_version(cfg_version) != found_version {
702+
return Err(Some(found_version));
703+
}
704+
705+
Ok(())
694706
}
695707

696708
fn root_pos(&self) -> NonZero<usize> {

0 commit comments

Comments
 (0)