(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(b: u64) -> char {
98 let b = (b & 0xf) as u8;
99 let b = match b {
100 0 .. 9 => '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:- 2992: 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 {