Move metadata header and version checks together

This will make it easier to report rustc versions for older metadata
formats.
This commit is contained in:
bjorn3 2024-03-08 14:49:28 +00:00
parent 14fbc3c005
commit fdff4d7682
3 changed files with 79 additions and 45 deletions

View File

@ -676,6 +676,7 @@ fn list_metadata(early_dcx: &EarlyDiagCtxt, sess: &Session, metadata_loader: &dy
metadata_loader, metadata_loader,
&mut v, &mut v,
&sess.opts.unstable_opts.ls, &sess.opts.unstable_opts.ls,
sess.cfg_version,
) )
.unwrap(); .unwrap();
safe_println!("{}", String::from_utf8(v).unwrap()); safe_println!("{}", String::from_utf8(v).unwrap());

View File

@ -569,8 +569,13 @@ fn extract_one(
debug!("skipping empty file"); debug!("skipping empty file");
continue; continue;
} }
let (hash, metadata) = let (hash, metadata) = match get_metadata_section(
match get_metadata_section(self.target, flavor, &lib, self.metadata_loader) { self.target,
flavor,
&lib,
self.metadata_loader,
self.cfg_version,
) {
Ok(blob) => { Ok(blob) => {
if let Some(h) = self.crate_matches(&blob, &lib) { if let Some(h) = self.crate_matches(&blob, &lib) {
(h, blob) (h, blob)
@ -579,14 +584,25 @@ fn extract_one(
continue; continue;
} }
} }
Err(MetadataError::VersionMismatch { expected_version, found_version }) => {
// The file was present and created by the same compiler version, but we
// couldn't load it for some reason. Give a hard error instead of silently
// ignoring it, but only if we would have given an error anyway.
info!(
"Rejecting via version: expected {} got {}",
expected_version, found_version
);
self.crate_rejections
.via_version
.push(CrateMismatch { path: lib, got: found_version });
continue;
}
Err(MetadataError::LoadFailure(err)) => { Err(MetadataError::LoadFailure(err)) => {
info!("no metadata found: {}", err); info!("no metadata found: {}", err);
// The file was present and created by the same compiler version, but we // The file was present and created by the same compiler version, but we
// couldn't load it for some reason. Give a hard error instead of silently // couldn't load it for some reason. Give a hard error instead of silently
// ignoring it, but only if we would have given an error anyway. // ignoring it, but only if we would have given an error anyway.
self.crate_rejections self.crate_rejections.via_invalid.push(CrateMismatch { path: lib, got: err });
.via_invalid
.push(CrateMismatch { path: lib, got: err });
continue; continue;
} }
Err(err @ MetadataError::NotPresent(_)) => { Err(err @ MetadataError::NotPresent(_)) => {
@ -648,16 +664,6 @@ fn extract_one(
} }
fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> { fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> {
let rustc_version = rustc_version(self.cfg_version);
let found_version = metadata.get_rustc_version();
if found_version != rustc_version {
info!("Rejecting via version: expected {} got {}", rustc_version, found_version);
self.crate_rejections
.via_version
.push(CrateMismatch { path: libpath.to_path_buf(), got: found_version });
return None;
}
let header = metadata.get_header(); let header = metadata.get_header();
if header.is_proc_macro_crate != self.is_proc_macro { if header.is_proc_macro_crate != self.is_proc_macro {
info!( info!(
@ -770,6 +776,7 @@ fn get_metadata_section<'p>(
flavor: CrateFlavor, flavor: CrateFlavor,
filename: &'p Path, filename: &'p Path,
loader: &dyn MetadataLoader, loader: &dyn MetadataLoader,
cfg_version: &'static str,
) -> Result<MetadataBlob, MetadataError<'p>> { ) -> Result<MetadataBlob, MetadataError<'p>> {
if !filename.exists() { if !filename.exists() {
return Err(MetadataError::NotPresent(filename)); return Err(MetadataError::NotPresent(filename));
@ -847,13 +854,18 @@ fn get_metadata_section<'p>(
} }
}; };
let blob = MetadataBlob(raw_bytes); let blob = MetadataBlob(raw_bytes);
if blob.is_compatible() { match blob.check_compatibility(cfg_version) {
Ok(blob) Ok(()) => Ok(blob),
} else { Err(None) => Err(MetadataError::LoadFailure(format!(
Err(MetadataError::LoadFailure(format!(
"invalid metadata version found: {}", "invalid metadata version found: {}",
filename.display() filename.display()
))) ))),
Err(Some(found_version)) => {
return Err(MetadataError::VersionMismatch {
expected_version: rustc_version(cfg_version),
found_version,
});
}
} }
} }
@ -864,9 +876,10 @@ pub fn list_file_metadata(
metadata_loader: &dyn MetadataLoader, metadata_loader: &dyn MetadataLoader,
out: &mut dyn Write, out: &mut dyn Write,
ls_kinds: &[String], ls_kinds: &[String],
cfg_version: &'static str,
) -> IoResult<()> { ) -> IoResult<()> {
let flavor = get_flavor_from_path(path); let flavor = get_flavor_from_path(path);
match get_metadata_section(target, flavor, path, metadata_loader) { match get_metadata_section(target, flavor, path, metadata_loader, cfg_version) {
Ok(metadata) => metadata.list_crate_metadata(out, ls_kinds), Ok(metadata) => metadata.list_crate_metadata(out, ls_kinds),
Err(msg) => write!(out, "{msg}\n"), Err(msg) => write!(out, "{msg}\n"),
} }
@ -932,6 +945,8 @@ enum MetadataError<'a> {
NotPresent(&'a Path), NotPresent(&'a Path),
/// The file was present and invalid. /// The file was present and invalid.
LoadFailure(String), LoadFailure(String),
/// The file was present, but compiled with a different rustc version.
VersionMismatch { expected_version: String, found_version: String },
} }
impl fmt::Display for MetadataError<'_> { impl fmt::Display for MetadataError<'_> {
@ -941,6 +956,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&format!("no such file: '{}'", filename.display())) f.write_str(&format!("no such file: '{}'", filename.display()))
} }
MetadataError::LoadFailure(msg) => f.write_str(msg), MetadataError::LoadFailure(msg) => f.write_str(msg),
MetadataError::VersionMismatch { expected_version, found_version } => {
f.write_str(&format!(
"rustc version mismatch. expected {}, found {}",
expected_version, found_version,
))
}
} }
} }
} }

View File

@ -684,13 +684,25 @@ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
implement_ty_decoder!(DecodeContext<'a, 'tcx>); implement_ty_decoder!(DecodeContext<'a, 'tcx>);
impl MetadataBlob { impl MetadataBlob {
pub(crate) fn is_compatible(&self) -> bool { pub(crate) fn check_compatibility(
self.blob().starts_with(METADATA_HEADER) &self,
cfg_version: &'static str,
) -> Result<(), Option<String>> {
if !self.blob().starts_with(METADATA_HEADER) {
if self.blob().starts_with(b"rust") {
return Err(Some("<unknown rustc version>".to_owned()));
}
return Err(None);
} }
pub(crate) fn get_rustc_version(&self) -> String { let found_version =
LazyValue::<String>::from_position(NonZero::new(METADATA_HEADER.len() + 8).unwrap()) LazyValue::<String>::from_position(NonZero::new(METADATA_HEADER.len() + 8).unwrap())
.decode(self) .decode(self);
if rustc_version(cfg_version) != found_version {
return Err(Some(found_version));
}
Ok(())
} }
fn root_pos(&self) -> NonZero<usize> { fn root_pos(&self) -> NonZero<usize> {