summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2016-07-02 14:41:31 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2016-07-02 14:43:52 +0300
commite154687f579f63b487a10c1028a675266dd9e764 (patch)
treec1c102d6818b0b183385d604b9db1a0a85b06d9b
parent0b36fff4d7c0f1d314e4e550bbb8e023bb33ba20 (diff)
downloadrust-e154687f579f63b487a10c1028a675266dd9e764.tar.gz
add a encoding version to the actual metadata
previously, only .so files included a metadata encoding version, *outside* of the zlib compressed area. This adds an encoding version inside the metadata itself, in both .so and .rlib files. Fixes #33778.
-rw-r--r--src/librustc_metadata/cstore.rs26
-rw-r--r--src/librustc_metadata/encoder.rs25
-rw-r--r--src/librustc_metadata/loader.rs26
3 files changed, 59 insertions, 18 deletions
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 7573929ab2c..774d0f7ea18 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -15,6 +15,7 @@
pub use self::MetadataBlob::*;
+use common;
use creader;
use decoder;
use index;
@@ -328,20 +329,25 @@ impl CrateMetadata {
}
impl MetadataBlob {
- pub fn as_slice<'a>(&'a self) -> &'a [u8] {
- let slice = match *self {
+ pub fn as_slice_raw<'a>(&'a self) -> &'a [u8] {
+ match *self {
MetadataVec(ref vec) => &vec[..],
MetadataArchive(ref ar) => ar.as_slice(),
- };
- if slice.len() < 4 {
+ }
+ }
+
+ pub fn as_slice<'a>(&'a self) -> &'a [u8] {
+ let slice = self.as_slice_raw();
+ let len_offset = 4 + common::metadata_encoding_version.len();
+ if slice.len() < len_offset+4 {
&[] // corrupt metadata
} else {
- let len = (((slice[0] as u32) << 24) |
- ((slice[1] as u32) << 16) |
- ((slice[2] as u32) << 8) |
- ((slice[3] as u32) << 0)) as usize;
- if len + 4 <= slice.len() {
- &slice[4.. len + 4]
+ let len = (((slice[len_offset+0] as u32) << 24) |
+ ((slice[len_offset+1] as u32) << 16) |
+ ((slice[len_offset+2] as u32) << 8) |
+ ((slice[len_offset+3] as u32) << 0)) as usize;
+ if len <= slice.len() - 4 - len_offset {
+ &slice[len_offset + 4..len_offset + len + 4]
} else {
&[] // corrupt or old metadata
}
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index e0aba86db41..b6f49569958 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1832,12 +1832,25 @@ pub fn encode_metadata(ecx: EncodeContext, krate: &hir::Crate) -> Vec<u8> {
// the length of the metadata to the start of the metadata. Later on this
// will allow us to slice the metadata to the precise length that we just
// generated regardless of trailing bytes that end up in it.
- let len = v.len() as u32;
- v.insert(0, (len >> 0) as u8);
- v.insert(0, (len >> 8) as u8);
- v.insert(0, (len >> 16) as u8);
- v.insert(0, (len >> 24) as u8);
- return v;
+ //
+ // We also need to store the metadata encoding version here, because
+ // rlibs don't have it. To get older versions of rustc to ignore
+ // this metadata, there are 4 zero bytes at the start, which are
+ // treated as a length of 0 by old compilers.
+
+ let len = v.len();
+ let mut result = vec![];
+ result.push(0);
+ result.push(0);
+ result.push(0);
+ result.push(0);
+ result.extend(metadata_encoding_version.iter().cloned());
+ result.push((len >> 24) as u8);
+ result.push((len >> 16) as u8);
+ result.push((len >> 8) as u8);
+ result.push((len >> 0) as u8);
+ result.extend(v);
+ result
}
fn encode_metadata_inner(rbml_w: &mut Encoder,
diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs
index 03d2b6b30da..edfdbf2aeef 100644
--- a/src/librustc_metadata/loader.rs
+++ b/src/librustc_metadata/loader.rs
@@ -767,6 +767,21 @@ impl ArchiveMetadata {
pub fn as_slice<'a>(&'a self) -> &'a [u8] { unsafe { &*self.data } }
}
+fn verify_decompressed_encoding_version(blob: &MetadataBlob, filename: &Path)
+ -> Result<(), String>
+{
+ let data = blob.as_slice_raw();
+ if data.len() < 4+metadata_encoding_version.len() ||
+ !<[u8]>::eq(&data[..4], &[0, 0, 0, 0]) ||
+ &data[4..4+metadata_encoding_version.len()] != metadata_encoding_version
+ {
+ Err((format!("incompatible metadata version found: '{}'",
+ filename.display())))
+ } else {
+ Ok(())
+ }
+}
+
// Just a small wrapper to time how long reading metadata takes.
fn get_metadata_section(target: &Target, flavor: CrateFlavor, filename: &Path)
-> Result<MetadataBlob, String> {
@@ -797,7 +812,10 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat
return match ArchiveMetadata::new(archive).map(|ar| MetadataArchive(ar)) {
None => Err(format!("failed to read rlib metadata: '{}'",
filename.display())),
- Some(blob) => Ok(blob)
+ Some(blob) => {
+ try!(verify_decompressed_encoding_version(&blob, filename));
+ Ok(blob)
+ }
};
}
unsafe {
@@ -842,7 +860,11 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat
csz - vlen);
let bytes = slice::from_raw_parts(cvbuf1, csz - vlen);
match flate::inflate_bytes(bytes) {
- Ok(inflated) => return Ok(MetadataVec(inflated)),
+ Ok(inflated) => {
+ let blob = MetadataVec(inflated);
+ try!(verify_decompressed_encoding_version(&blob, filename));
+ return Ok(blob);
+ }
Err(_) => {}
}
}