Skip to content

Commit 1065559

Browse files
committed
Move metadata header and version checks together
This will make it easier to report rustc versions for older metadata formats.
1 parent 2eb24d9 commit 1065559

File tree

3 files changed

+73
-49
lines changed

3 files changed

+73
-49
lines changed

compiler/rustc_driver_impl/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,7 @@ fn list_metadata(early_dcx: &EarlyDiagCtxt, sess: &Session, metadata_loader: &dy
679679
metadata_loader,
680680
&mut v,
681681
&sess.opts.unstable_opts.ls,
682+
sess.cfg_version,
682683
)
683684
.unwrap();
684685
safe_println!("{}", String::from_utf8(v).unwrap());

compiler/rustc_metadata/src/locator.rs

Lines changed: 56 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,6 @@ use std::{cmp, fmt};
243243
pub(crate) struct CrateLocator<'a> {
244244
// Immutable per-session configuration.
245245
only_needs_metadata: bool,
246-
sysroot: &'a Path,
247246
metadata_loader: &'a dyn MetadataLoader,
248247
cfg_version: &'static str,
249248

@@ -319,7 +318,6 @@ impl<'a> CrateLocator<'a> {
319318

320319
CrateLocator {
321320
only_needs_metadata,
322-
sysroot: &sess.sysroot,
323321
metadata_loader,
324322
cfg_version: sess.cfg_version,
325323
crate_name,
@@ -569,31 +567,47 @@ impl<'a> CrateLocator<'a> {
569567
debug!("skipping empty file");
570568
continue;
571569
}
572-
let (hash, metadata) =
573-
match get_metadata_section(self.target, flavor, &lib, self.metadata_loader) {
574-
Ok(blob) => {
575-
if let Some(h) = self.crate_matches(&blob, &lib) {
576-
(h, blob)
577-
} else {
578-
info!("metadata mismatch");
579-
continue;
580-
}
581-
}
582-
Err(MetadataError::LoadFailure(err)) => {
583-
info!("no metadata found: {}", err);
584-
// The file was present and created by the same compiler version, but we
585-
// couldn't load it for some reason. Give a hard error instead of silently
586-
// ignoring it, but only if we would have given an error anyway.
587-
self.crate_rejections
588-
.via_invalid
589-
.push(CrateMismatch { path: lib, got: err });
590-
continue;
591-
}
592-
Err(err @ MetadataError::NotPresent(_)) => {
593-
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");
594582
continue;
595583
}
596-
};
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+
};
597611
// If we see multiple hashes, emit an error about duplicate candidates.
598612
if slot.as_ref().is_some_and(|s| s.0 != hash) {
599613
if let Some(candidates) = err_data {
@@ -622,16 +636,6 @@ impl<'a> CrateLocator<'a> {
622636
}
623637

624638
fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> {
625-
let rustc_version = rustc_version(self.cfg_version);
626-
let found_version = metadata.get_rustc_version();
627-
if found_version != rustc_version {
628-
info!("Rejecting via version: expected {} got {}", rustc_version, found_version);
629-
self.crate_rejections
630-
.via_version
631-
.push(CrateMismatch { path: libpath.to_path_buf(), got: found_version });
632-
return None;
633-
}
634-
635639
let header = metadata.get_header();
636640
if header.is_proc_macro_crate != self.is_proc_macro {
637641
info!(
@@ -744,6 +748,7 @@ fn get_metadata_section<'p>(
744748
flavor: CrateFlavor,
745749
filename: &'p Path,
746750
loader: &dyn MetadataLoader,
751+
cfg_version: &'static str,
747752
) -> Result<MetadataBlob, MetadataError<'p>> {
748753
if !filename.exists() {
749754
return Err(MetadataError::NotPresent(filename));
@@ -821,13 +826,12 @@ fn get_metadata_section<'p>(
821826
}
822827
};
823828
let blob = MetadataBlob(raw_bytes);
824-
if blob.is_compatible() {
825-
Ok(blob)
826-
} else {
827-
Err(MetadataError::LoadFailure(format!(
828-
"invalid metadata version found: {}",
829-
filename.display()
830-
)))
829+
match blob.check_compatibility(cfg_version) {
830+
Ok(()) => Ok(blob),
831+
Err(version) => Err(MetadataError::VersionMismatch {
832+
expected_version: cfg_version,
833+
found_version: version,
834+
}),
831835
}
832836
}
833837

@@ -838,9 +842,10 @@ pub fn list_file_metadata(
838842
metadata_loader: &dyn MetadataLoader,
839843
out: &mut dyn Write,
840844
ls_kinds: &[String],
845+
cfg_version: &'static str,
841846
) -> IoResult<()> {
842847
let flavor = get_flavor_from_path(path);
843-
match get_metadata_section(target, flavor, path, metadata_loader) {
848+
match get_metadata_section(target, flavor, path, metadata_loader, cfg_version) {
844849
Ok(metadata) => metadata.list_crate_metadata(out, ls_kinds),
845850
Err(msg) => write!(out, "{msg}\n"),
846851
}
@@ -906,6 +911,8 @@ enum MetadataError<'a> {
906911
NotPresent(&'a Path),
907912
/// The file was present and invalid.
908913
LoadFailure(String),
914+
/// The file was present, but compiled with a different rustc version.
915+
VersionMismatch { expected_version: &'static str, found_version: String },
909916
}
910917

911918
impl fmt::Display for MetadataError<'_> {
@@ -915,6 +922,12 @@ impl fmt::Display for MetadataError<'_> {
915922
f.write_str(&format!("no such file: '{}'", filename.display()))
916923
}
917924
MetadataError::LoadFailure(msg) => f.write_str(msg),
925+
MetadataError::VersionMismatch { expected_version, found_version } => {
926+
f.write_str(&format!(
927+
"rustc version mismatch. expected {}, found {}",
928+
expected_version, found_version,
929+
))
930+
}
918931
}
919932
}
920933
}

compiler/rustc_metadata/src/rmeta/decoder.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -680,13 +680,23 @@ impl<'a, 'tcx, I: Idx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyTable<I, T>
680680
implement_ty_decoder!(DecodeContext<'a, 'tcx>);
681681

682682
impl MetadataBlob {
683-
pub(crate) fn is_compatible(&self) -> bool {
684-
self.blob().starts_with(METADATA_HEADER)
685-
}
683+
pub(crate) fn check_compatibility(&self, cfg_version: &'static str) -> Result<(), String> {
684+
if !self.blob().starts_with(METADATA_HEADER) {
685+
if self.blob().starts_with(b"rust") {
686+
return Err("<unknown rustc version>".to_string());
687+
}
688+
return Err("<invalid metadata header>".to_string());
689+
}
686690

687-
pub(crate) fn get_rustc_version(&self) -> String {
688-
LazyValue::<String>::from_position(NonZeroUsize::new(METADATA_HEADER.len() + 8).unwrap())
689-
.decode(self)
691+
let found_version = LazyValue::<String>::from_position(
692+
NonZeroUsize::new(METADATA_HEADER.len() + 4).unwrap(),
693+
)
694+
.decode(self);
695+
if rustc_version(cfg_version) != found_version {
696+
return Err(found_version);
697+
}
698+
699+
Ok(())
690700
}
691701

692702
fn root_pos(&self) -> NonZeroUsize {

0 commit comments

Comments
 (0)