]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #37931 - eddyb:meta-version, r=jseyfried
authorbors <bors@rust-lang.org>
Wed, 23 Nov 2016 23:48:44 +0000 (17:48 -0600)
committerGitHub <noreply@github.com>
Wed, 23 Nov 2016 23:48:44 +0000 (17:48 -0600)
rustc_metadata: don't break the version check when CrateRoot changes.

In #36551 I made `rustc_version` a field of `CrateRoot`, but despite it being the first field, one could still break the version check by changing `CrateRoot` so older compilers couldn't fully decode it (e.g. #37463).

This PR fixes #37803 by moving the version string back at the beginning of metadata, right after the 32-bit big-endian absolute position of `CrateRoot`, and by incrementing `METADATA_VERSION`.

1  2 
src/librustc_metadata/decoder.rs
src/librustc_metadata/locator.rs

index 8a187bb97969a385145c1e098a26e60c8ea28b01,25045679e71bce89d6fc45cecda7ec513605c055..f59f2bcc074764c42bf61f55e5da3a6729239536
@@@ -88,9 -88,8 +88,9 @@@ pub trait Metadata<'a, 'tcx>: Copy 
  impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob {
      fn raw_bytes(self) -> &'a [u8] {
          match *self {
 -            MetadataBlob::Inflated(ref vec) => &vec[..],
 +            MetadataBlob::Inflated(ref vec) => vec,
              MetadataBlob::Archive(ref ar) => ar.as_slice(),
 +            MetadataBlob::Raw(ref vec) => vec,
          }
      }
  }
@@@ -421,6 -420,10 +421,10 @@@ impl<'a, 'tcx> MetadataBlob 
          self.raw_bytes().starts_with(METADATA_HEADER)
      }
  
+     pub fn get_rustc_version(&self) -> String {
+         Lazy::with_position(METADATA_HEADER.len() + 4).decode(self)
+     }
      pub fn get_root(&self) -> CrateRoot {
          let slice = self.raw_bytes();
          let offset = METADATA_HEADER.len();
index be9284baa74cbabe6f37d9c7e3b9e36b1894fe7e,106d479c12c9dd75574baa2e78a16265d2ccaf75..868bc363791350d53e322af81e3e99c426157579
  //! is a platform-defined dynamic library. Each library has a metadata somewhere
  //! inside of it.
  //!
 +//! A third kind of dependency is an rmeta file. These are metadata files and do
 +//! not contain any code, etc. To a first approximation, these are treated in the
 +//! same way as rlibs. Where there is both an rlib and an rmeta file, the rlib
 +//! gets priority (even if the rmeta file is newer). An rmeta file is only
 +//! useful for checking a downstream crate, attempting to link one will cause an
 +//! error.
 +//!
  //! When translating a crate name to a crate on the filesystem, we all of a
  //! sudden need to take into account both rlibs and dylibs! Linkage later on may
  //! use either one of these files, as each has their pros/cons. The job of crate
@@@ -240,8 -233,8 +240,8 @@@ use rustc_back::target::Target
  
  use std::cmp;
  use std::fmt;
 -use std::fs;
 -use std::io;
 +use std::fs::{self, File};
 +use std::io::{self, Read};
  use std::path::{Path, PathBuf};
  use std::ptr;
  use std::slice;
@@@ -283,7 -276,6 +283,7 @@@ pub struct CratePaths 
      pub ident: String,
      pub dylib: Option<PathBuf>,
      pub rlib: Option<PathBuf>,
 +    pub rmeta: Option<PathBuf>,
  }
  
  pub const METADATA_FILENAME: &'static str = "rust.metadata.bin";
  #[derive(Copy, Clone, PartialEq)]
  enum CrateFlavor {
      Rlib,
 +    Rmeta,
      Dylib,
  }
  
@@@ -299,7 -290,6 +299,7 @@@ impl fmt::Display for CrateFlavor 
      fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
          f.write_str(match *self {
              CrateFlavor::Rlib => "rlib",
 +            CrateFlavor::Rmeta => "rmeta",
              CrateFlavor::Dylib => "dylib",
          })
      }
  
  impl CratePaths {
      fn paths(&self) -> Vec<PathBuf> {
 -        match (&self.dylib, &self.rlib) {
 -            (&None, &None) => vec![],
 -            (&Some(ref p), &None) |
 -            (&None, &Some(ref p)) => vec![p.clone()],
 -            (&Some(ref p1), &Some(ref p2)) => vec![p1.clone(), p2.clone()],
 -        }
 +        self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()).cloned().collect()
      }
  }
  
@@@ -463,35 -458,32 +463,35 @@@ impl<'a> Context<'a> 
                  None => return FileDoesntMatch,
                  Some(file) => file,
              };
 -            let (hash, rlib) = if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rlib") {
 -                (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], true)
 -            } else if file.starts_with(&dylib_prefix) &&
 -                                         file.ends_with(&dypair.1) {
 -                (&file[(dylib_prefix.len())..(file.len() - dypair.1.len())], false)
 -            } else {
 -                if file.starts_with(&staticlib_prefix[..]) && file.ends_with(&staticpair.1) {
 -                    staticlibs.push(CrateMismatch {
 -                        path: path.to_path_buf(),
 -                        got: "static".to_string(),
 -                    });
 -                }
 -                return FileDoesntMatch;
 -            };
 +            let (hash, found_kind) =
 +                if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rlib") {
 +                    (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib)
 +                } else if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rmeta") {
 +                    (&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta)
 +                } else if file.starts_with(&dylib_prefix) &&
 +                                             file.ends_with(&dypair.1) {
 +                    (&file[(dylib_prefix.len())..(file.len() - dypair.1.len())], CrateFlavor::Dylib)
 +                } else {
 +                    if file.starts_with(&staticlib_prefix[..]) && file.ends_with(&staticpair.1) {
 +                        staticlibs.push(CrateMismatch {
 +                            path: path.to_path_buf(),
 +                            got: "static".to_string(),
 +                        });
 +                    }
 +                    return FileDoesntMatch;
 +                };
              info!("lib candidate: {}", path.display());
  
              let hash_str = hash.to_string();
              let slot = candidates.entry(hash_str)
 -                .or_insert_with(|| (FxHashMap(), FxHashMap()));
 -            let (ref mut rlibs, ref mut dylibs) = *slot;
 +                .or_insert_with(|| (FxHashMap(), FxHashMap(), FxHashMap()));
 +            let (ref mut rlibs, ref mut rmetas, ref mut dylibs) = *slot;
              fs::canonicalize(path)
                  .map(|p| {
 -                    if rlib {
 -                        rlibs.insert(p, kind);
 -                    } else {
 -                        dylibs.insert(p, kind);
 +                    match found_kind {
 +                        CrateFlavor::Rlib => { rlibs.insert(p, kind); }
 +                        CrateFlavor::Rmeta => { rmetas.insert(p, kind); }
 +                        CrateFlavor::Dylib => { dylibs.insert(p, kind); }
                      }
                      FileMatches
                  })
          // libraries corresponds to the crate id and hash criteria that this
          // search is being performed for.
          let mut libraries = FxHashMap();
 -        for (_hash, (rlibs, dylibs)) in candidates {
 +        for (_hash, (rlibs, rmetas, dylibs)) in candidates {
              let mut slot = None;
              let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot);
 +            let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot);
              let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot);
              if let Some((h, m)) = slot {
                  libraries.insert(h,
                                   Library {
                                       dylib: dylib,
                                       rlib: rlib,
 +                                     rmeta: rmeta,
                                       metadata: m,
                                   });
              }
      }
  
      fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> {
-         let root = metadata.get_root();
-         if let Some(is_proc_macro) = self.is_proc_macro {
-             if root.macro_derive_registrar.is_some() != is_proc_macro {
-                 return None;
-             }
-         }
          let rustc_version = rustc_version();
-         if root.rustc_version != rustc_version {
+         let found_version = metadata.get_rustc_version();
+         if found_version != rustc_version {
              info!("Rejecting via version: expected {} got {}",
                    rustc_version,
-                   root.rustc_version);
+                   found_version);
              self.rejected_via_version.push(CrateMismatch {
                  path: libpath.to_path_buf(),
-                 got: root.rustc_version,
+                 got: found_version,
              });
              return None;
          }
  
+         let root = metadata.get_root();
+         if let Some(is_proc_macro) = self.is_proc_macro {
+             if root.macro_derive_registrar.is_some() != is_proc_macro {
+                 return None;
+             }
+         }
          if self.should_match_name {
              if self.crate_name != root.name {
                  info!("Rejecting via crate name");
          let sess = self.sess;
          let dylibname = self.dylibname();
          let mut rlibs = FxHashMap();
 +        let mut rmetas = FxHashMap();
          let mut dylibs = FxHashMap();
          {
              let locs = locs.map(|l| PathBuf::from(l)).filter(|loc| {
                          return false;
                      }
                  };
 -                if file.starts_with("lib") && file.ends_with(".rlib") {
 +                if file.starts_with("lib") &&
 +                   (file.ends_with(".rlib") || file.ends_with(".rmeta")) {
                      return true;
                  } else {
                      let (ref prefix, ref suffix) = dylibname;
              for loc in locs {
                  if loc.file_name().unwrap().to_str().unwrap().ends_with(".rlib") {
                      rlibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag);
 +                } else if loc.file_name().unwrap().to_str().unwrap().ends_with(".rmeta") {
 +                    rmetas.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag);
                  } else {
                      dylibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag);
                  }
          // Extract the rlib/dylib pair.
          let mut slot = None;
          let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot);
 +        let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot);
          let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot);
  
 -        if rlib.is_none() && dylib.is_none() {
 +        if rlib.is_none() && rmeta.is_none() && dylib.is_none() {
              return None;
          }
          match slot {
                  Some(Library {
                      dylib: dylib,
                      rlib: rlib,
 +                    rmeta: rmeta,
                      metadata: metadata,
                  })
              }
@@@ -867,15 -852,6 +868,15 @@@ fn get_metadata_section_imp(target: &Ta
                  Ok(blob)
              }
          };
 +    } else if flavor == CrateFlavor::Rmeta {
 +        let mut file = File::open(filename).map_err(|_|
 +            format!("could not open file: '{}'", filename.display()))?;
 +        let mut buf = vec![];
 +        file.read_to_end(&mut buf).map_err(|_|
 +            format!("failed to read rlib metadata: '{}'", filename.display()))?;
 +        let blob = MetadataBlob::Raw(buf);
 +        verify_decompressed_encoding_version(&blob, filename)?;
 +        return Ok(blob);
      }
      unsafe {
          let buf = common::path2cstr(filename);
@@@ -959,8 -935,6 +960,8 @@@ pub fn list_file_metadata(target: &Targ
      let filename = path.file_name().unwrap().to_str().unwrap();
      let flavor = if filename.ends_with(".rlib") {
          CrateFlavor::Rlib
 +    } else if filename.ends_with(".rmeta") {
 +        CrateFlavor::Rmeta
      } else {
          CrateFlavor::Dylib
      };