Skip to content

Commit e8342de

Browse files
Rollup merge of rust-lang#88368 - jyn514:metadata-error, r=petrochenkov
Improve error when an .rlib can't be parsed This usually describes either an error in the compiler itself or some sort of IO error. Either way, we should report it to the user rather than just saying "crate not found". This only gives an error if the crate couldn't be loaded at all - if the compiler finds another .rlib or .rmeta file which was valid, it will continue to compile the crate. Example output: ``` error[E0785]: found invalid metadata files for crate `foo` --> bar.rs:3:24 | 3 | println!("{}", foo::FOO_11_49[0]); | ^^^ | = warning: failed to parse rlib '/home/joshua/test-rustdoc/libfoo.rlib': Invalid archive extended name offset ``` cc `@ehuss`
2 parents 497ee32 + 8549598 commit e8342de

File tree

10 files changed

+122
-16
lines changed

10 files changed

+122
-16
lines changed

compiler/rustc_error_codes/src/error_codes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,7 @@ E0782: include_str!("./error_codes/E0782.md"),
481481
E0783: include_str!("./error_codes/E0783.md"),
482482
E0784: include_str!("./error_codes/E0784.md"),
483483
E0785: include_str!("./error_codes/E0785.md"),
484+
E0786: include_str!("./error_codes/E0786.md"),
484485
;
485486
// E0006, // merged with E0005
486487
// E0008, // cannot bind by-move into a pattern guard
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
A metadata file was invalid.
2+
3+
Erroneous code example:
4+
5+
```ignore (needs extern files)
6+
use ::foo; // error: found invalid metadata files for crate `foo`
7+
```
8+
9+
When loading crates, each crate must have a valid metadata file.
10+
Invalid files could be caused by filesystem corruption,
11+
an IO error while reading the file, or (rarely) a bug in the compiler itself.
12+
13+
Consider deleting the file and recreating it,
14+
or reporting a bug against the compiler.

compiler/rustc_metadata/src/locator.rs

+74-15
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ impl<'a> CrateLocator<'a> {
349349
self.crate_rejections.via_kind.clear();
350350
self.crate_rejections.via_version.clear();
351351
self.crate_rejections.via_filename.clear();
352+
self.crate_rejections.via_invalid.clear();
352353
}
353354

354355
crate fn maybe_load_library_crate(&mut self) -> Result<Option<Library>, CrateError> {
@@ -538,7 +539,16 @@ impl<'a> CrateLocator<'a> {
538539
continue;
539540
}
540541
}
541-
Err(err) => {
542+
Err(MetadataError::LoadFailure(err)) => {
543+
// The file was present and created by the same compiler version, but we
544+
// couldn't load it for some reason. Give a hard error instead of silently
545+
// ignoring it, but only if we would have given an error anyway.
546+
self.crate_rejections
547+
.via_invalid
548+
.push(CrateMismatch { path: lib, got: err });
549+
continue;
550+
}
551+
Err(err @ MetadataError::NotPresent(_)) => {
542552
warn!("no metadata found: {}", err);
543553
continue;
544554
}
@@ -716,25 +726,28 @@ impl<'a> CrateLocator<'a> {
716726
fn get_metadata_section(
717727
target: &Target,
718728
flavor: CrateFlavor,
719-
filename: &Path,
729+
filename: &'p Path,
720730
loader: &dyn MetadataLoader,
721-
) -> Result<MetadataBlob, String> {
731+
) -> Result<MetadataBlob, MetadataError<'p>> {
722732
if !filename.exists() {
723-
return Err(format!("no such file: '{}'", filename.display()));
733+
return Err(MetadataError::NotPresent(filename));
724734
}
725735
let raw_bytes: MetadataRef = match flavor {
726-
CrateFlavor::Rlib => loader.get_rlib_metadata(target, filename)?,
736+
CrateFlavor::Rlib => {
737+
loader.get_rlib_metadata(target, filename).map_err(MetadataError::LoadFailure)?
738+
}
727739
CrateFlavor::Dylib => {
728-
let buf = loader.get_dylib_metadata(target, filename)?;
740+
let buf =
741+
loader.get_dylib_metadata(target, filename).map_err(MetadataError::LoadFailure)?;
729742
// The header is uncompressed
730743
let header_len = METADATA_HEADER.len();
731744
debug!("checking {} bytes of metadata-version stamp", header_len);
732745
let header = &buf[..cmp::min(header_len, buf.len())];
733746
if header != METADATA_HEADER {
734-
return Err(format!(
735-
"incompatible metadata version found: '{}'",
747+
return Err(MetadataError::LoadFailure(format!(
748+
"invalid metadata version found: {}",
736749
filename.display()
737-
));
750+
)));
738751
}
739752

740753
// Header is okay -> inflate the actual metadata
@@ -744,17 +757,28 @@ fn get_metadata_section(
744757
match FrameDecoder::new(compressed_bytes).read_to_end(&mut inflated) {
745758
Ok(_) => rustc_erase_owner!(OwningRef::new(inflated).map_owner_box()),
746759
Err(_) => {
747-
return Err(format!("failed to decompress metadata: {}", filename.display()));
760+
return Err(MetadataError::LoadFailure(format!(
761+
"failed to decompress metadata: {}",
762+
filename.display()
763+
)));
748764
}
749765
}
750766
}
751767
CrateFlavor::Rmeta => {
752768
// mmap the file, because only a small fraction of it is read.
753-
let file = std::fs::File::open(filename)
754-
.map_err(|_| format!("failed to open rmeta metadata: '{}'", filename.display()))?;
769+
let file = std::fs::File::open(filename).map_err(|_| {
770+
MetadataError::LoadFailure(format!(
771+
"failed to open rmeta metadata: '{}'",
772+
filename.display()
773+
))
774+
})?;
755775
let mmap = unsafe { Mmap::map(file) };
756-
let mmap = mmap
757-
.map_err(|_| format!("failed to mmap rmeta metadata: '{}'", filename.display()))?;
776+
let mmap = mmap.map_err(|_| {
777+
MetadataError::LoadFailure(format!(
778+
"failed to mmap rmeta metadata: '{}'",
779+
filename.display()
780+
))
781+
})?;
758782

759783
rustc_erase_owner!(OwningRef::new(mmap).map_owner_box())
760784
}
@@ -763,7 +787,10 @@ fn get_metadata_section(
763787
if blob.is_compatible() {
764788
Ok(blob)
765789
} else {
766-
Err(format!("incompatible metadata version found: '{}'", filename.display()))
790+
Err(MetadataError::LoadFailure(format!(
791+
"invalid metadata version found: {}",
792+
filename.display()
793+
)))
767794
}
768795
}
769796

@@ -842,6 +869,7 @@ struct CrateRejections {
842869
via_kind: Vec<CrateMismatch>,
843870
via_version: Vec<CrateMismatch>,
844871
via_filename: Vec<CrateMismatch>,
872+
via_invalid: Vec<CrateMismatch>,
845873
}
846874

847875
/// Candidate rejection reasons collected during crate search.
@@ -871,6 +899,24 @@ crate enum CrateError {
871899
NonDylibPlugin(Symbol),
872900
}
873901

902+
enum MetadataError<'a> {
903+
/// The file was missing.
904+
NotPresent(&'a Path),
905+
/// The file was present and invalid.
906+
LoadFailure(String),
907+
}
908+
909+
impl fmt::Display for MetadataError<'_> {
910+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
911+
match self {
912+
MetadataError::NotPresent(filename) => {
913+
f.write_str(&format!("no such file: '{}'", filename.display()))
914+
}
915+
MetadataError::LoadFailure(msg) => f.write_str(msg),
916+
}
917+
}
918+
}
919+
874920
impl CrateError {
875921
crate fn report(self, sess: &Session, span: Span, missing_core: bool) -> ! {
876922
let mut err = match self {
@@ -1044,6 +1090,19 @@ impl CrateError {
10441090
}
10451091
err.note(&msg);
10461092
err
1093+
} else if !locator.crate_rejections.via_invalid.is_empty() {
1094+
let mut err = struct_span_err!(
1095+
sess,
1096+
span,
1097+
E0786,
1098+
"found invalid metadata files for crate `{}`{}",
1099+
crate_name,
1100+
add,
1101+
);
1102+
for CrateMismatch { path: _, got } in locator.crate_rejections.via_invalid {
1103+
err.note(&got);
1104+
}
1105+
err
10471106
} else {
10481107
let mut err = struct_span_err!(
10491108
sess,

src/test/run-make-fulldeps/invalid-library/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
all:
44
touch $(TMPDIR)/lib.rmeta
55
$(AR) crus $(TMPDIR)/libfoo-ffffffff-1.0.rlib $(TMPDIR)/lib.rmeta
6-
$(RUSTC) foo.rs 2>&1 | $(CGREP) "can't find crate for"
6+
$(RUSTC) foo.rs 2>&1 | $(CGREP) "found invalid metadata"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

src/test/ui/crate-loading/auxiliary/libfoo.rlib

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// compile-flags: --crate-type lib --extern foo={{src-base}}/crate-loading/auxiliary/libfoo.rlib
2+
// edition:2018
3+
#![no_std]
4+
use ::foo; //~ ERROR invalid metadata files for crate `foo`
5+
//~| NOTE memory map must have a non-zero length
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0786]: found invalid metadata files for crate `foo`
2+
--> $DIR/invalid-rlib.rs:4:7
3+
|
4+
LL | use ::foo;
5+
| ^^^
6+
|
7+
= note: failed to mmap file '$DIR/auxiliary/libfoo.rlib': memory map must have a non-zero length
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0786`.
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// compile-flags: --crate-type lib --extern bar={{src-base}}/crate-loading/auxiliary/libbar.so
2+
// edition:2018
3+
use ::bar; //~ ERROR invalid metadata files for crate `bar`
4+
//~| NOTE invalid metadata version
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0786]: found invalid metadata files for crate `bar`
2+
--> $DIR/invalid-so.rs:3:7
3+
|
4+
LL | use ::bar;
5+
| ^^^
6+
|
7+
= note: invalid metadata version found: $DIR/auxiliary/libbar.so
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0786`.

0 commit comments

Comments
 (0)