(index<- )        ./librustc/back/svh.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri Apr 25 22:40:04 2014
   1  // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  //! Calculation and management of a Strict Version Hash for crates
  12  //!
  13  //! # Today's ABI problem
  14  //!
  15  //! In today's implementation of rustc, it is incredibly difficult to achieve
  16  //! forward binary compatibility without resorting to C-like interfaces. Within
  17  //! rust code itself, abi details such as symbol names suffer from a variety of
  18  //! unrelated factors to code changing such as the "def id drift" problem. This
  19  //! ends up yielding confusing error messages about metadata mismatches and
  20  //! such.
  21  //!
  22  //! The core of this problem is when an upstream dependency changes and
  23  //! downstream dependents are not recompiled. This causes compile errors because
  24  //! the upstream crate's metadata has changed but the downstream crates are
  25  //! still referencing the older crate's metadata.
  26  //!
  27  //! This problem exists for many reasons, the primary of which is that rust does
  28  //! not currently support forwards ABI compatibility (in place upgrades of a
  29  //! crate).
  30  //!
  31  //! # SVH and how it alleviates the problem
  32  //!
  33  //! With all of this knowledge on hand, this module contains the implementation
  34  //! of a notion of a "Strict Version Hash" for a crate. This is essentially a
  35  //! hash of all contents of a crate which can somehow be exposed to downstream
  36  //! crates.
  37  //!
  38  //! This hash is currently calculated by just hashing the AST, but this is
  39  //! obviously wrong (doc changes should not result in an incompatible ABI).
  40  //! Implementation-wise, this is required at this moment in time.
  41  //!
  42  //! By encoding this strict version hash into all crate's metadata, stale crates
  43  //! can be detected immediately and error'd about by rustc itself.
  44  //!
  45  //! # Relevant links
  46  //!
  47  //! Original issue: https://github.com/mozilla/rust/issues/10207
  48  
  49  use std::fmt;
  50  use std::hash::Hash;
  51  use std::hash::sip::SipState;
  52  use std::iter::range_step;
  53  use syntax::ast;
  54  
  55  #[deriving(Clone, Eq)]
  56  pub struct Svh {
  57      hash: ~str,
  58  }
  59  
  60  impl Svh {
  61      pub fn new(hash&str) -> Svh {
  62          assert!(hash.len() == 16);
  63          Svh { hash: hash.to_owned() }
  64      }
  65  
  66      pub fn as_str<'a>(&'a self) -> &'a str {
  67          self.hash.as_slice()
  68      }
  69  
  70      pub fn calculate(krate&ast::Crate) -> Svh {
  71          // FIXME: see above for why this is wrong, it shouldn't just hash the
  72          //        crate.  Fixing this would require more in-depth analysis in
  73          //        this function about what portions of the crate are reachable
  74          //        in tandem with bug fixes throughout the rest of the compiler.
  75          //
  76          //        Note that for now we actually exclude some top-level things
  77          //        from the crate like the CrateConfig/span. The CrateConfig
  78          //        contains command-line `--cfg` flags, so this means that the
  79          //        stage1/stage2 AST for libstd and such is different hash-wise
  80          //        when it's actually the exact same representation-wise.
  81          //
  82          //        As a first stab at only hashing the relevant parts of the
  83          //        AST, this only hashes the module/attrs, not the CrateConfig
  84          //        field.
  85          //
  86          // FIXME: this should use SHA1, not SipHash. SipHash is not built to
  87          //        avoid collisions.
  88          let mut state = SipState::new();
  89          krate.module.hash(&mut state);
  90          krate.attrs.hash(&mut state);
  91  
  92          let hash = state.result();
  93          return Svh {
  94              hash: range_step(0, 64, 4).map(|i| hex(hash >> i)).collect()
  95          };
  96  
  97          fn hex(bu64) -> char {
  98              let b = (b & 0xf) as u8;
  99              let b = match b {
 100                  0 .. => '0' as u8 + b,
 101                  _ => 'a' as u8 + b - 10,
 102              };
 103              b as char
 104          }
 105      }
 106  }
 107  
 108  impl fmt::Show for Svh {
 109      fn fmt(&self, f&mut fmt::Formatter) -> fmt::Result {
 110          f.pad(self.as_str())
 111      }
 112  }


librustc/back/svh.rs:55:23-55:23 -struct- definition:
pub struct Svh {
    hash: ~str,
}
references:- 29
92:         let hash = state.result();
93:         return Svh {
94:             hash: range_step(0, 64, 4).map(|i| hex(hash >> i)).collect()
--
108: impl fmt::Show for Svh {
109:     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
librustc/metadata/common.rs:
210:     pub crateid: CrateId,
211:     pub crate_hash: Svh,
212: }
librustc/metadata/encoder.rs:
1680: fn encode_hash(ebml_w: &mut Encoder, hash: &Svh) {
1681:     ebml_w.start_tag(tag_crate_hash);
librustc/metadata/decoder.rs:
1072: fn list_crate_attributes(md: ebml::Doc, hash: &Svh,
1073:                          out: &mut io::Writer) -> io::IoResult<()> {
--
1134: pub fn get_crate_hash(data: &[u8]) -> Svh {
1135:     let cratedoc = reader::Doc(data);
librustc/metadata/creader.rs:
318:                  crate_id: &CrateId,
319:                  hash: Option<&Svh>,
320:                  span: Span)
librustc/metadata/cstore.rs:
215:     pub fn crate_id(&self) -> CrateId { decoder::get_crate_id(self.data()) }
216:     pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
217: }
librustc/metadata/loader.rs:
72:     pub id_hash: &'a str,
73:     pub hash: Option<&'a Svh>,
74:     pub triple: &'a str,
librustc/middle/ty.rs:
4479: /// context it's calculated within. This is used by the `type_id` intrinsic.
4480: pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 {
4481:     let mut state = sip::SipState::new();
librustc/back/svh.rs:
56: pub struct Svh {