]> git.lizzy.rs Git - rust.git/commitdiff
add a encoding version to the actual metadata
authorAriel Ben-Yehuda <ariel.byd@gmail.com>
Sat, 2 Jul 2016 11:41:31 +0000 (14:41 +0300)
committerAriel Ben-Yehuda <ariel.byd@gmail.com>
Sat, 2 Jul 2016 11:43:52 +0000 (14:43 +0300)
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
src/librustc_metadata/encoder.rs
src/librustc_metadata/loader.rs

index 7573929ab2c04f7ec918736726cede309ae9d490..774d0f7ea188608820c21df7a014c87ecdac6cfb 100644 (file)
@@ -15,6 +15,7 @@
 
 pub use self::MetadataBlob::*;
 
+use common;
 use creader;
 use decoder;
 use index;
@@ -328,20 +329,25 @@ pub fn panic_strategy(&self) -> PanicStrategy {
 }
 
 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
             }
index e0aba86db416b710606f51b3a0ad6ea29c7f308f..b6f49569958d68189effffc864b47396c1029410 100644 (file)
@@ -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,
index 03d2b6b30da31df2cde2fc4bc9c6e174e3850100..edfdbf2aeefa8ab201bc9b8a724723e56d9279ba 100644 (file)
@@ -767,6 +767,21 @@ fn new(ar: ArchiveRO) -> Option<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(_) => {}
                 }
             }