Auto merge of #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`
This commit is contained in:
commit
5fa94f3c57
@ -484,6 +484,7 @@
|
||||
E0783: include_str!("./error_codes/E0783.md"),
|
||||
E0784: include_str!("./error_codes/E0784.md"),
|
||||
E0785: include_str!("./error_codes/E0785.md"),
|
||||
E0786: include_str!("./error_codes/E0786.md"),
|
||||
;
|
||||
// E0006, // merged with E0005
|
||||
// E0008, // cannot bind by-move into a pattern guard
|
||||
|
14
compiler/rustc_error_codes/src/error_codes/E0786.md
Normal file
14
compiler/rustc_error_codes/src/error_codes/E0786.md
Normal file
@ -0,0 +1,14 @@
|
||||
A metadata file was invalid.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```ignore (needs extern files)
|
||||
use ::foo; // error: found invalid metadata files for crate `foo`
|
||||
```
|
||||
|
||||
When loading crates, each crate must have a valid metadata file.
|
||||
Invalid files could be caused by filesystem corruption,
|
||||
an IO error while reading the file, or (rarely) a bug in the compiler itself.
|
||||
|
||||
Consider deleting the file and recreating it,
|
||||
or reporting a bug against the compiler.
|
@ -350,6 +350,7 @@ impl<'a> CrateLocator<'a> {
|
||||
self.crate_rejections.via_kind.clear();
|
||||
self.crate_rejections.via_version.clear();
|
||||
self.crate_rejections.via_filename.clear();
|
||||
self.crate_rejections.via_invalid.clear();
|
||||
}
|
||||
|
||||
crate fn maybe_load_library_crate(&mut self) -> Result<Option<Library>, CrateError> {
|
||||
@ -548,7 +549,17 @@ fn extract_one(
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
Err(MetadataError::LoadFailure(err)) => {
|
||||
info!("no metadata found: {}", err);
|
||||
// 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.
|
||||
self.crate_rejections
|
||||
.via_invalid
|
||||
.push(CrateMismatch { path: lib, got: err });
|
||||
continue;
|
||||
}
|
||||
Err(err @ MetadataError::NotPresent(_)) => {
|
||||
info!("no metadata found: {}", err);
|
||||
continue;
|
||||
}
|
||||
@ -726,25 +737,28 @@ fn find_commandline_library(&mut self) -> Result<Option<Library>, CrateError> {
|
||||
fn get_metadata_section(
|
||||
target: &Target,
|
||||
flavor: CrateFlavor,
|
||||
filename: &Path,
|
||||
filename: &'p Path,
|
||||
loader: &dyn MetadataLoader,
|
||||
) -> Result<MetadataBlob, String> {
|
||||
) -> Result<MetadataBlob, MetadataError<'p>> {
|
||||
if !filename.exists() {
|
||||
return Err(format!("no such file: '{}'", filename.display()));
|
||||
return Err(MetadataError::NotPresent(filename));
|
||||
}
|
||||
let raw_bytes: MetadataRef = match flavor {
|
||||
CrateFlavor::Rlib => loader.get_rlib_metadata(target, filename)?,
|
||||
CrateFlavor::Rlib => {
|
||||
loader.get_rlib_metadata(target, filename).map_err(MetadataError::LoadFailure)?
|
||||
}
|
||||
CrateFlavor::Dylib => {
|
||||
let buf = loader.get_dylib_metadata(target, filename)?;
|
||||
let buf =
|
||||
loader.get_dylib_metadata(target, filename).map_err(MetadataError::LoadFailure)?;
|
||||
// The header is uncompressed
|
||||
let header_len = METADATA_HEADER.len();
|
||||
debug!("checking {} bytes of metadata-version stamp", header_len);
|
||||
let header = &buf[..cmp::min(header_len, buf.len())];
|
||||
if header != METADATA_HEADER {
|
||||
return Err(format!(
|
||||
"incompatible metadata version found: '{}'",
|
||||
return Err(MetadataError::LoadFailure(format!(
|
||||
"invalid metadata version found: {}",
|
||||
filename.display()
|
||||
));
|
||||
)));
|
||||
}
|
||||
|
||||
// Header is okay -> inflate the actual metadata
|
||||
@ -756,17 +770,28 @@ fn get_metadata_section(
|
||||
match FrameDecoder::new(compressed_bytes).read_to_end(&mut inflated) {
|
||||
Ok(_) => rustc_erase_owner!(OwningRef::new(inflated).map_owner_box()),
|
||||
Err(_) => {
|
||||
return Err(format!("failed to decompress metadata: {}", filename.display()));
|
||||
return Err(MetadataError::LoadFailure(format!(
|
||||
"failed to decompress metadata: {}",
|
||||
filename.display()
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
CrateFlavor::Rmeta => {
|
||||
// mmap the file, because only a small fraction of it is read.
|
||||
let file = std::fs::File::open(filename)
|
||||
.map_err(|_| format!("failed to open rmeta metadata: '{}'", filename.display()))?;
|
||||
let file = std::fs::File::open(filename).map_err(|_| {
|
||||
MetadataError::LoadFailure(format!(
|
||||
"failed to open rmeta metadata: '{}'",
|
||||
filename.display()
|
||||
))
|
||||
})?;
|
||||
let mmap = unsafe { Mmap::map(file) };
|
||||
let mmap = mmap
|
||||
.map_err(|_| format!("failed to mmap rmeta metadata: '{}'", filename.display()))?;
|
||||
let mmap = mmap.map_err(|_| {
|
||||
MetadataError::LoadFailure(format!(
|
||||
"failed to mmap rmeta metadata: '{}'",
|
||||
filename.display()
|
||||
))
|
||||
})?;
|
||||
|
||||
rustc_erase_owner!(OwningRef::new(mmap).map_owner_box())
|
||||
}
|
||||
@ -775,7 +800,10 @@ fn get_metadata_section(
|
||||
if blob.is_compatible() {
|
||||
Ok(blob)
|
||||
} else {
|
||||
Err(format!("incompatible metadata version found: '{}'", filename.display()))
|
||||
Err(MetadataError::LoadFailure(format!(
|
||||
"invalid metadata version found: {}",
|
||||
filename.display()
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -854,6 +882,7 @@ struct CrateRejections {
|
||||
via_kind: Vec<CrateMismatch>,
|
||||
via_version: Vec<CrateMismatch>,
|
||||
via_filename: Vec<CrateMismatch>,
|
||||
via_invalid: Vec<CrateMismatch>,
|
||||
}
|
||||
|
||||
/// Candidate rejection reasons collected during crate search.
|
||||
@ -883,6 +912,24 @@ struct CrateRejections {
|
||||
NonDylibPlugin(Symbol),
|
||||
}
|
||||
|
||||
enum MetadataError<'a> {
|
||||
/// The file was missing.
|
||||
NotPresent(&'a Path),
|
||||
/// The file was present and invalid.
|
||||
LoadFailure(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for MetadataError<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
MetadataError::NotPresent(filename) => {
|
||||
f.write_str(&format!("no such file: '{}'", filename.display()))
|
||||
}
|
||||
MetadataError::LoadFailure(msg) => f.write_str(msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CrateError {
|
||||
crate fn report(self, sess: &Session, span: Span, missing_core: bool) -> ! {
|
||||
let mut err = match self {
|
||||
@ -1064,6 +1111,19 @@ impl CrateError {
|
||||
}
|
||||
err.note(&msg);
|
||||
err
|
||||
} else if !locator.crate_rejections.via_invalid.is_empty() {
|
||||
let mut err = struct_span_err!(
|
||||
sess,
|
||||
span,
|
||||
E0786,
|
||||
"found invalid metadata files for crate `{}`{}",
|
||||
crate_name,
|
||||
add,
|
||||
);
|
||||
for CrateMismatch { path: _, got } in locator.crate_rejections.via_invalid {
|
||||
err.note(&got);
|
||||
}
|
||||
err
|
||||
} else {
|
||||
let mut err = struct_span_err!(
|
||||
sess,
|
||||
|
@ -3,4 +3,4 @@
|
||||
all:
|
||||
touch $(TMPDIR)/lib.rmeta
|
||||
$(AR) crus $(TMPDIR)/libfoo-ffffffff-1.0.rlib $(TMPDIR)/lib.rmeta
|
||||
$(RUSTC) foo.rs 2>&1 | $(CGREP) "can't find crate for"
|
||||
$(RUSTC) foo.rs 2>&1 | $(CGREP) "found invalid metadata"
|
||||
|
7
src/test/run-make/invalid-so/Makefile
Normal file
7
src/test/run-make/invalid-so/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
include ../../run-make-fulldeps/tools.mk
|
||||
|
||||
DYLIB_NAME := $(shell echo | $(RUSTC) --crate-name foo --crate-type dylib --print file-names -)
|
||||
|
||||
all:
|
||||
echo >> $(TMPDIR)/$(DYLIB_NAME)
|
||||
$(RUSTC) --crate-type lib --extern foo=$(TMPDIR)/$(DYLIB_NAME) bar.rs 2>&1 | $(CGREP) 'invalid metadata files for crate `foo`'
|
1
src/test/run-make/invalid-so/bar.rs
Normal file
1
src/test/run-make/invalid-so/bar.rs
Normal file
@ -0,0 +1 @@
|
||||
extern crate foo;
|
0
src/test/ui/crate-loading/auxiliary/libfoo.rlib
Normal file
0
src/test/ui/crate-loading/auxiliary/libfoo.rlib
Normal file
8
src/test/ui/crate-loading/invalid-rlib.rs
Normal file
8
src/test/ui/crate-loading/invalid-rlib.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// compile-flags: --crate-type lib --extern foo={{src-base}}/crate-loading/auxiliary/libfoo.rlib
|
||||
// normalize-stderr-test: "failed to mmap file '.*auxiliary/libfoo.rlib':.*" -> "failed to mmap file 'auxiliary/libfoo.rlib'"
|
||||
// don't emit warn logging, it's basically the same as the errors and it's annoying to normalize
|
||||
// rustc-env:RUSTC_LOG=error
|
||||
// edition:2018
|
||||
#![no_std]
|
||||
use ::foo; //~ ERROR invalid metadata files for crate `foo`
|
||||
//~| NOTE failed to mmap file
|
11
src/test/ui/crate-loading/invalid-rlib.stderr
Normal file
11
src/test/ui/crate-loading/invalid-rlib.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error[E0786]: found invalid metadata files for crate `foo`
|
||||
--> $DIR/invalid-rlib.rs:7:7
|
||||
|
|
||||
LL | use ::foo;
|
||||
| ^^^
|
||||
|
|
||||
= note: failed to mmap file 'auxiliary/libfoo.rlib'
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0786`.
|
Loading…
Reference in New Issue
Block a user