make the metadata lock more robust and bump the metadata encoding version

check the metadata lock when loading rather than afterwards

Fixes #33733
Fixes #33015
This commit is contained in:
Ariel Ben-Yehuda 2016-07-02 00:36:33 +03:00
parent c333ebbe63
commit 0b36fff4d7
5 changed files with 38 additions and 31 deletions

View File

@ -252,3 +252,7 @@ pub fn rustc_version() -> String {
}
pub const tag_panic_strategy: usize = 0x114;
// NB: increment this if you change the format of metadata such that
// rustc_version can't be found.
pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2];

View File

@ -12,7 +12,6 @@
//! Validates all used crates and extern libraries and loads their metadata
use common::rustc_version;
use cstore::{self, CStore, CrateSource, MetadataBlob};
use decoder;
use loader::{self, CratePaths};
@ -236,25 +235,6 @@ impl<'a> CrateReader<'a> {
return ret;
}
fn verify_rustc_version(&self,
name: &str,
span: Span,
metadata: &MetadataBlob) {
let crate_rustc_version = decoder::crate_rustc_version(metadata.as_slice());
if crate_rustc_version != Some(rustc_version()) {
let mut err = struct_span_fatal!(self.sess, span, E0514,
"the crate `{}` has been compiled with {}, which is \
incompatible with this version of rustc",
name,
crate_rustc_version
.as_ref().map(|s| &**s)
.unwrap_or("an old version of rustc"));
err.help("consider removing the compiled binaries and recompiling \
with your current version of rustc");
err.emit();
}
}
fn verify_no_symbol_conflicts(&self,
span: Span,
metadata: &MetadataBlob) {
@ -296,7 +276,6 @@ impl<'a> CrateReader<'a> {
explicitly_linked: bool)
-> (ast::CrateNum, Rc<cstore::CrateMetadata>,
cstore::CrateSource) {
self.verify_rustc_version(name, span, &lib.metadata);
self.verify_no_symbol_conflicts(span, &lib.metadata);
// Claim this crate number and cache it
@ -381,6 +360,7 @@ impl<'a> CrateReader<'a> {
rejected_via_hash: vec!(),
rejected_via_triple: vec!(),
rejected_via_kind: vec!(),
rejected_via_version: vec!(),
should_match_name: true,
};
match self.load(&mut load_ctxt) {
@ -517,6 +497,7 @@ impl<'a> CrateReader<'a> {
rejected_via_hash: vec!(),
rejected_via_triple: vec!(),
rejected_via_kind: vec!(),
rejected_via_version: vec!(),
should_match_name: true,
};
let library = self.load(&mut load_ctxt).or_else(|| {

View File

@ -9,6 +9,7 @@
// except according to those terms.
use cstore;
use common;
use decoder;
use encoder;
use loader;
@ -588,7 +589,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
fn metadata_encoding_version(&self) -> &[u8]
{
encoder::metadata_encoding_version
common::metadata_encoding_version
}
/// Returns a map from a sufficiently visible external item (i.e. an external item that is

View File

@ -1799,10 +1799,6 @@ fn encode_panic_strategy(rbml_w: &mut Encoder, ecx: &EncodeContext) {
}
}
// NB: Increment this as you change the metadata encoding version.
#[allow(non_upper_case_globals)]
pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2 ];
pub fn encode_metadata(ecx: EncodeContext, krate: &hir::Crate) -> Vec<u8> {
let mut wr = Cursor::new(Vec::new());

View File

@ -213,8 +213,8 @@
//! metadata::loader or metadata::creader for all the juicy details!
use cstore::{MetadataBlob, MetadataVec, MetadataArchive};
use common::{metadata_encoding_version, rustc_version};
use decoder;
use encoder;
use rustc::hir::svh::Svh;
use rustc::session::Session;
@ -260,6 +260,7 @@ pub struct Context<'a> {
pub rejected_via_hash: Vec<CrateMismatch>,
pub rejected_via_triple: Vec<CrateMismatch>,
pub rejected_via_kind: Vec<CrateMismatch>,
pub rejected_via_version: Vec<CrateMismatch>,
pub should_match_name: bool,
}
@ -336,6 +337,10 @@ impl<'a> Context<'a> {
struct_span_err!(self.sess, self.span, E0462,
"found staticlib `{}` instead of rlib or dylib{}",
self.ident, add)
} else if !self.rejected_via_version.is_empty() {
struct_span_err!(self.sess, self.span, E0514,
"found crate `{}` compiled by an incompatible version of rustc{}",
self.ident, add)
} else {
struct_span_err!(self.sess, self.span, E0463,
"can't find crate for `{}`{}",
@ -350,7 +355,7 @@ impl<'a> Context<'a> {
}
}
if !self.rejected_via_hash.is_empty() {
err.note("perhaps this crate needs to be recompiled?");
err.note("perhaps that crate needs to be recompiled?");
let mismatches = self.rejected_via_hash.iter();
for (i, &CrateMismatch{ ref path, .. }) in mismatches.enumerate() {
err.note(&format!("crate `{}` path #{}: {}",
@ -367,13 +372,22 @@ impl<'a> Context<'a> {
}
}
if !self.rejected_via_kind.is_empty() {
err.help("please recompile this crate using --crate-type lib");
err.help("please recompile that crate using --crate-type lib");
let mismatches = self.rejected_via_kind.iter();
for (i, &CrateMismatch { ref path, .. }) in mismatches.enumerate() {
err.note(&format!("crate `{}` path #{}: {}",
self.ident, i+1, path.display()));
}
}
if !self.rejected_via_version.is_empty() {
err.help(&format!("please recompile that crate using this compiler ({})",
rustc_version()));
let mismatches = self.rejected_via_version.iter();
for (i, &CrateMismatch { ref path, ref got }) in mismatches.enumerate() {
err.note(&format!("crate `{}` path #{}: {} compiled by {:?}",
self.ident, i+1, path.display(), got));
}
}
err.emit();
self.sess.abort_if_errors();
@ -591,6 +605,17 @@ impl<'a> Context<'a> {
}
fn crate_matches(&mut self, crate_data: &[u8], libpath: &Path) -> Option<Svh> {
let crate_rustc_version = decoder::crate_rustc_version(crate_data);
if crate_rustc_version != Some(rustc_version()) {
let message = crate_rustc_version.unwrap_or(format!("an unknown compiler"));
info!("Rejecting via version: expected {} got {}", rustc_version(), message);
self.rejected_via_version.push(CrateMismatch {
path: libpath.to_path_buf(),
got: message
});
return None;
}
if self.should_match_name {
match decoder::maybe_get_crate_name(crate_data) {
Some(ref name) if self.crate_name == *name => {}
@ -801,12 +826,12 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat
let cbuf = llvm::LLVMGetSectionContents(si.llsi);
let csz = llvm::LLVMGetSectionSize(si.llsi) as usize;
let cvbuf: *const u8 = cbuf as *const u8;
let vlen = encoder::metadata_encoding_version.len();
let vlen = metadata_encoding_version.len();
debug!("checking {} bytes of metadata-version stamp",
vlen);
let minsz = cmp::min(vlen, csz);
let buf0 = slice::from_raw_parts(cvbuf, minsz);
let version_ok = buf0 == encoder::metadata_encoding_version;
let version_ok = buf0 == metadata_encoding_version;
if !version_ok {
return Err((format!("incompatible metadata version found: '{}'",
filename.display())));