Skip to content

Commit bdfef5b

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 14fbc3c commit bdfef5b

File tree

3 files changed

+72
-47
lines changed

3 files changed

+72
-47
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

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

650666
fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> {
651-
let rustc_version = rustc_version(self.cfg_version);
652-
let found_version = metadata.get_rustc_version();
653-
if found_version != rustc_version {
654-
info!("Rejecting via version: expected {} got {}", rustc_version, found_version);
655-
self.crate_rejections
656-
.via_version
657-
.push(CrateMismatch { path: libpath.to_path_buf(), got: found_version });
658-
return None;
659-
}
660-
661667
let header = metadata.get_header();
662668
if header.is_proc_macro_crate != self.is_proc_macro {
663669
info!(
@@ -770,6 +776,7 @@ fn get_metadata_section<'p>(
770776
flavor: CrateFlavor,
771777
filename: &'p Path,
772778
loader: &dyn MetadataLoader,
779+
cfg_version: &'static str,
773780
) -> Result<MetadataBlob, MetadataError<'p>> {
774781
if !filename.exists() {
775782
return Err(MetadataError::NotPresent(filename));
@@ -847,13 +854,12 @@ fn get_metadata_section<'p>(
847854
}
848855
};
849856
let blob = MetadataBlob(raw_bytes);
850-
if blob.is_compatible() {
851-
Ok(blob)
852-
} else {
853-
Err(MetadataError::LoadFailure(format!(
854-
"invalid metadata version found: {}",
855-
filename.display()
856-
)))
857+
match blob.check_compatibility(cfg_version) {
858+
Ok(()) => Ok(blob),
859+
Err(version) => Err(MetadataError::VersionMismatch {
860+
expected_version: cfg_version,
861+
found_version: version,
862+
}),
857863
}
858864
}
859865

@@ -864,9 +870,10 @@ pub fn list_file_metadata(
864870
metadata_loader: &dyn MetadataLoader,
865871
out: &mut dyn Write,
866872
ls_kinds: &[String],
873+
cfg_version: &'static str,
867874
) -> IoResult<()> {
868875
let flavor = get_flavor_from_path(path);
869-
match get_metadata_section(target, flavor, path, metadata_loader) {
876+
match get_metadata_section(target, flavor, path, metadata_loader, cfg_version) {
870877
Ok(metadata) => metadata.list_crate_metadata(out, ls_kinds),
871878
Err(msg) => write!(out, "{msg}\n"),
872879
}
@@ -932,6 +939,8 @@ enum MetadataError<'a> {
932939
NotPresent(&'a Path),
933940
/// The file was present and invalid.
934941
LoadFailure(String),
942+
/// The file was present, but compiled with a different rustc version.
943+
VersionMismatch { expected_version: &'static str, found_version: String },
935944
}
936945

937946
impl fmt::Display for MetadataError<'_> {
@@ -941,6 +950,12 @@ impl fmt::Display for MetadataError<'_> {
941950
f.write_str(&format!("no such file: '{}'", filename.display()))
942951
}
943952
MetadataError::LoadFailure(msg) => f.write_str(msg),
953+
MetadataError::VersionMismatch { expected_version, found_version } => {
954+
f.write_str(&format!(
955+
"rustc version mismatch. expected {}, found {}",
956+
expected_version, found_version,
957+
))
958+
}
944959
}
945960
}
946961
}

compiler/rustc_metadata/src/rmeta/decoder.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -684,13 +684,22 @@ 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(&self, cfg_version: &'static str) -> Result<(), String> {
688+
if !self.blob().starts_with(METADATA_HEADER) {
689+
if self.blob().starts_with(b"rust") {
690+
return Err("<unknown rustc version>".to_string());
691+
}
692+
return Err("<invalid metadata header>".to_string());
693+
}
690694

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

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

0 commit comments

Comments
 (0)