From e154687f579f63b487a10c1028a675266dd9e764 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 2 Jul 2016 14:41:31 +0300 Subject: [PATCH] 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. --- src/librustc_metadata/cstore.rs | 26 ++++++++++++++++---------- src/librustc_metadata/encoder.rs | 25 +++++++++++++++++++------ src/librustc_metadata/loader.rs | 26 ++++++++++++++++++++++++-- 3 files changed, 59 insertions(+), 18 deletions(-) diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 7573929ab2c0..774d0f7ea188 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 e0aba86db416..b6f49569958d 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 { // 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 03d2b6b30da3..edfdbf2aeefa 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 { @@ -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(_) => {} } }