diff options
author | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2016-07-02 14:41:31 +0300 |
---|---|---|
committer | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2016-07-02 14:43:52 +0300 |
commit | e154687f579f63b487a10c1028a675266dd9e764 (patch) | |
tree | c1c102d6818b0b183385d604b9db1a0a85b06d9b | |
parent | 0b36fff4d7c0f1d314e4e550bbb8e023bb33ba20 (diff) | |
download | rust-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.rs | 26 | ||||
-rw-r--r-- | src/librustc_metadata/encoder.rs | 25 | ||||
-rw-r--r-- | 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 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(_) => {} } } |