diff --git a/Cargo.lock b/Cargo.lock index 15d016a97cf8c..64c60ab7b4ed5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,12 +87,6 @@ dependencies = [ "scoped_threadpool", ] -[[package]] -name = "arrayref" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" - [[package]] name = "arrayvec" version = "0.4.7" @@ -187,11 +181,22 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.3.3" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" dependencies = [ - "arrayref", "byte-tools", ] @@ -240,9 +245,9 @@ version = "0.1.0" [[package]] name = "byte-tools" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "bytecount" @@ -897,9 +902,9 @@ checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" [[package]] name = "digest" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" dependencies = [ "generic-array", ] @@ -1226,9 +1231,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.9.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" +checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" dependencies = [ "typenum", ] @@ -1962,6 +1967,17 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +[[package]] +name = "md-5" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18af3dcaf2b0219366cdb4e2af65a6101457b415c3d1a5c71dd9c2b7c77b9c8" +dependencies = [ + "block-buffer", + "digest", + "opaque-debug", +] + [[package]] name = "mdbook" version = "0.3.5" @@ -2250,6 +2266,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6a04cb71e910d0034815600180f62a95bf6e67942d7ab52a166a68c7d7e9cd0" +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + [[package]] name = "open" version = "1.2.1" @@ -2467,9 +2489,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.1.0" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5a3492a4ed208ffc247adcdcc7ba2a95be3104f58877d0d02f0df39bf3efb5e" +checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" dependencies = [ "maplit", "pest", @@ -4155,11 +4177,13 @@ dependencies = [ "arena", "cfg-if", "log", + "md-5", "rustc_data_structures", "rustc_index", "rustc_macros", "scoped-tls", "serialize", + "sha-1", "unicode-width", ] @@ -4535,14 +4559,14 @@ dependencies = [ [[package]] name = "sha-1" -version = "0.7.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" dependencies = [ "block-buffer", - "byte-tools", "digest", "fake-simd", + "opaque-debug", ] [[package]] diff --git a/src/doc/unstable-book/src/compiler-flags/src-hash-algorithm.md b/src/doc/unstable-book/src/compiler-flags/src-hash-algorithm.md new file mode 100644 index 0000000000000..5a7d0655a440a --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/src-hash-algorithm.md @@ -0,0 +1,11 @@ +# `src-hash-algorithm` + +The tracking issue for this feature is: [#70401](https://github.com/rust-lang/rust/issues/70401). + +------------------------ + +The `-Z src-hash-algorithm` compiler flag controls which algorithm is used when hashing each source file. The hash is stored in the debug info and can be used by a debugger to verify the source code matches the executable. + +Supported hash algorithms are: `md5`, and `sha1`. Note that not all hash algorithms are supported by all debug info formats. + +By default, the compiler chooses the hash algorithm based on the target specification. diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index a9e21c056a3eb..700f25d35bc1d 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -41,7 +41,7 @@ use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{self, DebugInfo}; use rustc_span::symbol::{Interner, Symbol}; -use rustc_span::{self, FileName, Span}; +use rustc_span::{self, FileName, SourceFileHash, Span}; use rustc_target::abi::{Abi, Align, DiscriminantKind, HasDataLayout, Integer, LayoutOf}; use rustc_target::abi::{Int, Pointer, F32, F64}; use rustc_target::abi::{Primitive, Size, VariantIdx, Variants}; @@ -751,6 +751,14 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp metadata } +fn hex_encode(data: &[u8]) -> String { + let mut hex_string = String::with_capacity(data.len() * 2); + for byte in data.iter() { + write!(&mut hex_string, "{:02x}", byte).unwrap(); + } + hex_string +} + pub fn file_metadata( cx: &CodegenCx<'ll, '_>, file_name: &FileName, @@ -758,6 +766,8 @@ pub fn file_metadata( ) -> &'ll DIFile { debug!("file_metadata: file_name: {}, defining_crate: {}", file_name, defining_crate); + let source_file = cx.sess().source_map().get_source_file(file_name); + let hash = source_file.as_ref().map(|f| &f.src_hash); let file_name = Some(file_name.to_string()); let directory = if defining_crate == LOCAL_CRATE { Some(cx.sess().working_dir.0.to_string_lossy().to_string()) @@ -766,17 +776,18 @@ pub fn file_metadata( // independent of the compiler's working directory one way or another. None }; - file_metadata_raw(cx, file_name, directory) + file_metadata_raw(cx, file_name, directory, hash) } pub fn unknown_file_metadata(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile { - file_metadata_raw(cx, None, None) + file_metadata_raw(cx, None, None, None) } fn file_metadata_raw( cx: &CodegenCx<'ll, '_>, file_name: Option, directory: Option, + hash: Option<&SourceFileHash>, ) -> &'ll DIFile { let key = (file_name, directory); @@ -789,6 +800,17 @@ fn file_metadata_raw( let file_name = file_name.as_deref().unwrap_or(""); let directory = directory.as_deref().unwrap_or(""); + let (hash_kind, hash_value) = match hash { + Some(hash) => { + let kind = match hash.kind { + rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5, + rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1, + }; + (kind, hex_encode(hash.hash_bytes())) + } + None => (llvm::ChecksumKind::None, String::new()), + }; + let file_metadata = unsafe { llvm::LLVMRustDIBuilderCreateFile( DIB(cx), @@ -796,6 +818,9 @@ fn file_metadata_raw( file_name.len(), directory.as_ptr().cast(), directory.len(), + hash_kind, + hash_value.as_ptr().cast(), + hash_value.len(), ) }; @@ -920,6 +945,9 @@ pub fn compile_unit_metadata( name_in_debuginfo.len(), work_dir.as_ptr().cast(), work_dir.len(), + llvm::ChecksumKind::None, + ptr::null(), + 0, ); let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit( diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 1d61d95cc6bf3..aeb34e5c9c954 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -546,6 +546,15 @@ pub enum ThreadLocalMode { LocalExec, } +/// LLVMRustChecksumKind +#[derive(Copy, Clone)] +#[repr(C)] +pub enum ChecksumKind { + None, + MD5, + SHA1, +} + extern "C" { type Opaque; } @@ -1640,6 +1649,9 @@ extern "C" { FilenameLen: size_t, Directory: *const c_char, DirectoryLen: size_t, + CSKind: ChecksumKind, + Checksum: *const c_char, + ChecksumLen: size_t, ) -> &'a DIFile; pub fn LLVMRustDIBuilderCreateSubroutineType( diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index a8cc34e185439..02bf1aded3bc3 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -22,7 +22,7 @@ use rustc_session::parse::CrateConfig; use rustc_session::CrateDisambiguator; use rustc_session::{config, early_error, filesearch, output, DiagnosticOutput, Session}; use rustc_span::edition::Edition; -use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMap}; +use rustc_span::source_map::{FileLoader, SourceMap}; use rustc_span::symbol::{sym, Symbol}; use smallvec::SmallVec; use std::env; @@ -62,15 +62,13 @@ pub fn create_session( lint_caps: FxHashMap, descriptions: Registry, ) -> (Lrc, Lrc>, Lrc) { - let loader = file_loader.unwrap_or(box RealFileLoader); - let source_map = Lrc::new(SourceMap::with_file_loader(loader, sopts.file_path_mapping())); - let mut sess = session::build_session_with_source_map( + let (mut sess, source_map) = session::build_session_with_source_map( sopts, input_path, descriptions, - source_map.clone(), diagnostic_output, lint_caps, + file_loader, ); let codegen_backend = get_codegen_backend(&sess); diff --git a/src/librustc_middle/ich/impls_syntax.rs b/src/librustc_middle/ich/impls_syntax.rs index c5a4b53b10df8..300aac19e51b0 100644 --- a/src/librustc_middle/ich/impls_syntax.rs +++ b/src/librustc_middle/ich/impls_syntax.rs @@ -61,7 +61,7 @@ impl<'a> HashStable> for SourceFile { cnum, // Do not hash the source as it is not encoded src: _, - src_hash, + ref src_hash, external_src: _, start_pos, end_pos: _, diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 54481bd124df5..58a03dbe388e6 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -18,9 +18,10 @@ use rustc_feature::UnstableFeatures; use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST}; use rustc_span::source_map::{FileName, FilePathMapping}; use rustc_span::symbol::{sym, Symbol}; +use rustc_span::SourceFileHashAlgorithm; use rustc_errors::emitter::HumanReadableErrorType; -use rustc_errors::{ColorConfig, FatalError, Handler, HandlerFlags}; +use rustc_errors::{ColorConfig, HandlerFlags}; use std::collections::btree_map::{ Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter, @@ -748,25 +749,30 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo user_cfg } -pub fn build_target_config(opts: &Options, sp: &Handler) -> Config { +pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Config { let target = Target::search(&opts.target_triple).unwrap_or_else(|e| { - sp.struct_fatal(&format!("Error loading target specification: {}", e)) - .help("Use `--print target-list` for a list of built-in targets") - .emit(); - FatalError.raise(); + early_error( + error_format, + &format!( + "Error loading target specification: {}. \ + Use `--print target-list` for a list of built-in targets", + e + ), + ) }); let ptr_width = match &target.target_pointer_width[..] { "16" => 16, "32" => 32, "64" => 64, - w => sp - .fatal(&format!( + w => early_error( + error_format, + &format!( "target specification was invalid: \ unrecognized target-pointer-width {}", w - )) - .raise(), + ), + ), }; Config { target, ptr_width } @@ -1971,7 +1977,8 @@ impl PpMode { crate mod dep_tracking { use super::{ CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel, - OutputTypes, Passes, Sanitizer, SwitchWithOptPath, SymbolManglingVersion, + OutputTypes, Passes, Sanitizer, SourceFileHashAlgorithm, SwitchWithOptPath, + SymbolManglingVersion, }; use crate::lint; use crate::utils::NativeLibraryKind; @@ -2049,6 +2056,7 @@ crate mod dep_tracking { impl_dep_tracking_hash_via_hash!(LinkerPluginLto); impl_dep_tracking_hash_via_hash!(SwitchWithOptPath); impl_dep_tracking_hash_via_hash!(SymbolManglingVersion); + impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_for_sortable_vec_of!(String); impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf); diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index 432f1e17ab312..3962e30335db2 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -10,6 +10,7 @@ use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel use rustc_feature::UnstableFeatures; use rustc_span::edition::Edition; +use rustc_span::SourceFileHashAlgorithm; use std::collections::BTreeMap; @@ -283,12 +284,14 @@ macro_rules! options { Some("one of: `disabled`, `trampolines`, or `aliases`"); pub const parse_symbol_mangling_version: Option<&str> = Some("either `legacy` or `v0` (RFC 2603)"); + pub const parse_src_file_hash: Option<&str> = + Some("either `md5`, or `sha1`"); } #[allow(dead_code)] mod $mod_set { use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath, - SymbolManglingVersion, CFGuard}; + SymbolManglingVersion, CFGuard, SourceFileHashAlgorithm}; use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel}; use std::path::PathBuf; use std::str::FromStr; @@ -622,6 +625,14 @@ macro_rules! options { }; true } + + fn parse_src_file_hash(slot: &mut Option, v: Option<&str>) -> bool { + match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) { + Some(hash_kind) => *slot = Some(hash_kind), + _ => return false, + } + true + } } ) } @@ -961,4 +972,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "use new LLVM pass manager"), link_native_libraries: Option = (None, parse_opt_bool, [UNTRACKED], "Link native libraries in the linker invocation."), + src_hash_algorithm: Option = (None, parse_src_file_hash, [TRACKED], + "hash algorithm of source files in debug info (`md5`, or `sha1`)"), } diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index b3d75143c5639..914a4503b5280 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -20,7 +20,8 @@ use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType}; use rustc_errors::json::JsonEmitter; use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId, ErrorReported}; use rustc_span::edition::Edition; -use rustc_span::source_map::{self, MultiSpan, Span}; +use rustc_span::source_map::{self, FileLoader, MultiSpan, RealFileLoader, SourceMap, Span}; +use rustc_span::SourceFileHashAlgorithm; use rustc_target::spec::{PanicStrategy, RelroLevel, Target, TargetTriple}; use std::cell::{self, RefCell}; @@ -854,16 +855,15 @@ pub fn build_session( local_crate_source_file: Option, registry: rustc_errors::registry::Registry, ) -> Session { - let file_path_mapping = sopts.file_path_mapping(); - build_session_with_source_map( sopts, local_crate_source_file, registry, - Lrc::new(source_map::SourceMap::new(file_path_mapping)), DiagnosticOutput::Default, Default::default(), + None, ) + .0 } fn default_emitter( @@ -940,10 +940,10 @@ pub fn build_session_with_source_map( sopts: config::Options, local_crate_source_file: Option, registry: rustc_errors::registry::Registry, - source_map: Lrc, diagnostics_output: DiagnosticOutput, - lint_caps: FxHashMap, -) -> Session { + driver_lint_caps: FxHashMap, + file_loader: Option>, +) -> (Session, Lrc) { // FIXME: This is not general enough to make the warning lint completely override // normal diagnostic warnings, since the warning lint can also be denied and changed // later via the source code. @@ -961,23 +961,33 @@ pub fn build_session_with_source_map( DiagnosticOutput::Default => None, DiagnosticOutput::Raw(write) => Some(write), }; + + let target_cfg = config::build_target_config(&sopts, sopts.error_format); + let host_triple = TargetTriple::from_triple(config::host_triple()); + let host = Target::search(&host_triple).unwrap_or_else(|e| { + early_error(sopts.error_format, &format!("Error loading host specification: {}", e)) + }); + + let loader = file_loader.unwrap_or(Box::new(RealFileLoader)); + let hash_kind = sopts.debugging_opts.src_hash_algorithm.unwrap_or_else(|| { + if target_cfg.target.options.is_like_msvc { + SourceFileHashAlgorithm::Sha1 + } else { + SourceFileHashAlgorithm::Md5 + } + }); + let source_map = Lrc::new(SourceMap::with_file_loader_and_hash_kind( + loader, + sopts.file_path_mapping(), + hash_kind, + )); let emitter = default_emitter(&sopts, registry, &source_map, write_dest); - let diagnostic_handler = rustc_errors::Handler::with_emitter_and_flags( + let span_diagnostic = rustc_errors::Handler::with_emitter_and_flags( emitter, sopts.debugging_opts.diagnostic_handler_flags(can_emit_warnings), ); - build_session_(sopts, local_crate_source_file, diagnostic_handler, source_map, lint_caps) -} - -fn build_session_( - sopts: config::Options, - local_crate_source_file: Option, - span_diagnostic: rustc_errors::Handler, - source_map: Lrc, - driver_lint_caps: FxHashMap, -) -> Session { let self_profiler = if let SwitchWithOptPath::Enabled(ref d) = sopts.debugging_opts.self_profile { let directory = @@ -999,13 +1009,7 @@ fn build_session_( None }; - let host_triple = TargetTriple::from_triple(config::host_triple()); - let host = Target::search(&host_triple).unwrap_or_else(|e| { - span_diagnostic.fatal(&format!("Error loading host specification: {}", e)).raise() - }); - let target_cfg = config::build_target_config(&sopts, &span_diagnostic); - - let parse_sess = ParseSess::with_span_handler(span_diagnostic, source_map); + let parse_sess = ParseSess::with_span_handler(span_diagnostic, source_map.clone()); let sysroot = match &sopts.maybe_sysroot { Some(sysroot) => sysroot.clone(), None => filesearch::get_or_default_sysroot(), @@ -1098,7 +1102,7 @@ fn build_session_( validate_commandline_args_with_session_available(&sess); - sess + (sess, source_map) } // If it is useful to have a Session available already for validating a diff --git a/src/librustc_span/Cargo.toml b/src/librustc_span/Cargo.toml index c3fa2331d2b16..1c2721260d69b 100644 --- a/src/librustc_span/Cargo.toml +++ b/src/librustc_span/Cargo.toml @@ -19,3 +19,5 @@ scoped-tls = "1.0" unicode-width = "0.1.4" cfg-if = "0.1.2" log = "0.4" +sha-1 = "0.8" +md-5 = "0.8" diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index 3bcc20d36e76c..0d9f3f214fb21 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -47,9 +47,14 @@ use std::borrow::Cow; use std::cell::RefCell; use std::cmp::{self, Ordering}; use std::fmt; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use std::ops::{Add, Sub}; use std::path::PathBuf; +use std::str::FromStr; + +use md5::Md5; +use sha1::Digest; +use sha1::Sha1; #[cfg(test)] mod tests; @@ -874,6 +879,70 @@ impl ExternalSource { #[derive(Debug)] pub struct OffsetOverflowError; +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +pub enum SourceFileHashAlgorithm { + Md5, + Sha1, +} + +impl FromStr for SourceFileHashAlgorithm { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "md5" => Ok(SourceFileHashAlgorithm::Md5), + "sha1" => Ok(SourceFileHashAlgorithm::Sha1), + _ => Err(()), + } + } +} + +rustc_data_structures::impl_stable_hash_via_hash!(SourceFileHashAlgorithm); + +/// The hash of the on-disk source file used for debug info. +#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)] +#[derive(HashStable_Generic)] +pub struct SourceFileHash { + pub kind: SourceFileHashAlgorithm, + value: [u8; 20], +} + +impl SourceFileHash { + pub fn new(kind: SourceFileHashAlgorithm, src: &str) -> SourceFileHash { + let mut hash = SourceFileHash { kind, value: Default::default() }; + let len = hash.hash_len(); + let value = &mut hash.value[..len]; + let data = src.as_bytes(); + match kind { + SourceFileHashAlgorithm::Md5 => { + value.copy_from_slice(&Md5::digest(data)); + } + SourceFileHashAlgorithm::Sha1 => { + value.copy_from_slice(&Sha1::digest(data)); + } + } + hash + } + + /// Check if the stored hash matches the hash of the string. + pub fn matches(&self, src: &str) -> bool { + Self::new(self.kind, src) == *self + } + + /// The bytes of the hash. + pub fn hash_bytes(&self) -> &[u8] { + let len = self.hash_len(); + &self.value[..len] + } + + fn hash_len(&self) -> usize { + match self.kind { + SourceFileHashAlgorithm::Md5 => 16, + SourceFileHashAlgorithm::Sha1 => 20, + } + } +} + /// A single source in the `SourceMap`. #[derive(Clone)] pub struct SourceFile { @@ -889,7 +958,7 @@ pub struct SourceFile { /// The complete source code. pub src: Option>, /// The source code's hash. - pub src_hash: u128, + pub src_hash: SourceFileHash, /// The external source code (used for external crates, which will have a `None` /// value as `self.src`. pub external_src: Lock, @@ -987,7 +1056,8 @@ impl Decodable for SourceFile { let name: FileName = d.read_struct_field("name", 0, |d| Decodable::decode(d))?; let name_was_remapped: bool = d.read_struct_field("name_was_remapped", 1, |d| Decodable::decode(d))?; - let src_hash: u128 = d.read_struct_field("src_hash", 2, |d| Decodable::decode(d))?; + let src_hash: SourceFileHash = + d.read_struct_field("src_hash", 2, |d| Decodable::decode(d))?; let start_pos: BytePos = d.read_struct_field("start_pos", 3, |d| Decodable::decode(d))?; let end_pos: BytePos = d.read_struct_field("end_pos", 4, |d| Decodable::decode(d))?; @@ -1062,14 +1132,12 @@ impl SourceFile { unmapped_path: FileName, mut src: String, start_pos: BytePos, + hash_kind: SourceFileHashAlgorithm, ) -> Self { + // Compute the file hash before any normalization. + let src_hash = SourceFileHash::new(hash_kind, &src); let normalized_pos = normalize_src(&mut src, start_pos); - let src_hash = { - let mut hasher: StableHasher = StableHasher::new(); - hasher.write(src.as_bytes()); - hasher.finish::() - }; let name_hash = { let mut hasher: StableHasher = StableHasher::new(); name.hash(&mut hasher); @@ -1125,10 +1193,7 @@ impl SourceFile { } = &mut *external_src { if let Some(src) = src { - let mut hasher: StableHasher = StableHasher::new(); - hasher.write(src.as_bytes()); - - if hasher.finish::() == self.src_hash { + if self.src_hash.matches(&src) { *src_kind = ExternalSourceKind::Present(Lrc::new(src)); return true; } diff --git a/src/librustc_span/source_map.rs b/src/librustc_span/source_map.rs index 57e68320f3fbb..49e2144b3e380 100644 --- a/src/librustc_span/source_map.rs +++ b/src/librustc_span/source_map.rs @@ -141,27 +141,31 @@ pub struct SourceMap { // This is used to apply the file path remapping as specified via // `--remap-path-prefix` to all `SourceFile`s allocated within this `SourceMap`. path_mapping: FilePathMapping, + + /// The algorithm used for hashing the contents of each source file. + hash_kind: SourceFileHashAlgorithm, } impl SourceMap { pub fn new(path_mapping: FilePathMapping) -> SourceMap { - SourceMap { - used_address_space: AtomicU32::new(0), - files: Default::default(), - file_loader: Box::new(RealFileLoader), + Self::with_file_loader_and_hash_kind( + Box::new(RealFileLoader), path_mapping, - } + SourceFileHashAlgorithm::Md5, + ) } - pub fn with_file_loader( + pub fn with_file_loader_and_hash_kind( file_loader: Box, path_mapping: FilePathMapping, + hash_kind: SourceFileHashAlgorithm, ) -> SourceMap { SourceMap { used_address_space: AtomicU32::new(0), files: Default::default(), file_loader, path_mapping, + hash_kind, } } @@ -275,6 +279,7 @@ impl SourceMap { unmapped_path, src, Pos::from_usize(start_pos), + self.hash_kind, )); let mut files = self.files.borrow_mut(); @@ -296,7 +301,7 @@ impl SourceMap { &self, filename: FileName, name_was_remapped: bool, - src_hash: u128, + src_hash: SourceFileHash, name_hash: u128, source_len: usize, cnum: CrateNum, diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 8c6548cd3c5b2..e80d16bb0c7ab 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -706,6 +706,30 @@ impl Decodable for Vec { } } +impl Encodable for [u8; 20] { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + s.emit_seq_elt(i, |s| e.encode(s))? + } + Ok(()) + }) + } +} + +impl Decodable for [u8; 20] { + fn decode(d: &mut D) -> Result<[u8; 20], D::Error> { + d.read_seq(|d, len| { + assert!(len == 20); + let mut v = [0u8; 20]; + for i in 0..len { + v[i] = d.read_seq_elt(i, |d| Decodable::decode(d))?; + } + Ok(v) + }) + } +} + impl<'a, T: Encodable> Encodable for Cow<'a, [T]> where [T]: ToOwned>, diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 799adb418822d..21094b3252089 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -640,6 +640,25 @@ static DICompileUnit::DebugEmissionKind fromRust(LLVMRustDebugEmissionKind Kind) } } +enum class LLVMRustChecksumKind { + None, + MD5, + SHA1, +}; + +static Optional fromRust(LLVMRustChecksumKind Kind) { + switch (Kind) { + case LLVMRustChecksumKind::None: + return None; + case LLVMRustChecksumKind::MD5: + return DIFile::ChecksumKind::CSK_MD5; + case LLVMRustChecksumKind::SHA1: + return DIFile::ChecksumKind::CSK_SHA1; + default: + report_fatal_error("bad ChecksumKind."); + } +} + extern "C" uint32_t LLVMRustDebugMetadataVersion() { return DEBUG_METADATA_VERSION; } @@ -686,9 +705,15 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateCompileUnit( extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFile( LLVMRustDIBuilderRef Builder, const char *Filename, size_t FilenameLen, - const char *Directory, size_t DirectoryLen) { + const char *Directory, size_t DirectoryLen, LLVMRustChecksumKind CSKind, + const char *Checksum, size_t ChecksumLen) { + Optional llvmCSKind = fromRust(CSKind); + Optional> CSInfo{}; + if (llvmCSKind) + CSInfo.emplace(*llvmCSKind, StringRef{Checksum, ChecksumLen}); return wrap(Builder->createFile(StringRef(Filename, FilenameLen), - StringRef(Directory, DirectoryLen))); + StringRef(Directory, DirectoryLen), + CSInfo)); } extern "C" LLVMMetadataRef diff --git a/src/test/codegen/remap_path_prefix/main.rs b/src/test/codegen/remap_path_prefix/main.rs index 4724dc3c3e593..20475bab0fc92 100644 --- a/src/test/codegen/remap_path_prefix/main.rs +++ b/src/test/codegen/remap_path_prefix/main.rs @@ -22,7 +22,7 @@ fn main() { } // Here we check that local debuginfo is mapped correctly. -// CHECK: !DIFile(filename: "/the/src/remap_path_prefix/main.rs", directory: "/the/cwd/") +// CHECK: !DIFile(filename: "/the/src/remap_path_prefix/main.rs", directory: "/the/cwd/" // And here that debuginfo from other crates are expanded to absolute paths. -// CHECK: !DIFile(filename: "/the/aux-src/remap_path_prefix_aux.rs", directory: "") +// CHECK: !DIFile(filename: "/the/aux-src/remap_path_prefix_aux.rs", directory: "" diff --git a/src/test/codegen/remap_path_prefix/xcrate-generic.rs b/src/test/codegen/remap_path_prefix/xcrate-generic.rs index 30d6112fd02f6..7a9d2ca9b6bbd 100644 --- a/src/test/codegen/remap_path_prefix/xcrate-generic.rs +++ b/src/test/codegen/remap_path_prefix/xcrate-generic.rs @@ -11,4 +11,4 @@ pub fn foo() { } // Here we check that local debuginfo is mapped correctly. -// CHECK: !DIFile(filename: "/the/aux-src/xcrate-generic.rs", directory: "") +// CHECK: !DIFile(filename: "/the/aux-src/xcrate-generic.rs", directory: "" diff --git a/src/test/codegen/src-hash-algorithm/src-hash-algorithm-md5.rs b/src/test/codegen/src-hash-algorithm/src-hash-algorithm-md5.rs new file mode 100644 index 0000000000000..64be1127786f1 --- /dev/null +++ b/src/test/codegen/src-hash-algorithm/src-hash-algorithm-md5.rs @@ -0,0 +1,6 @@ +// compile-flags: -g -Z src-hash-algorithm=md5 + +#![crate_type = "lib"] + +pub fn test() {} +// CHECK: checksumkind: CSK_MD5 diff --git a/src/test/codegen/src-hash-algorithm/src-hash-algorithm-sha1.rs b/src/test/codegen/src-hash-algorithm/src-hash-algorithm-sha1.rs new file mode 100644 index 0000000000000..54e07152142ec --- /dev/null +++ b/src/test/codegen/src-hash-algorithm/src-hash-algorithm-sha1.rs @@ -0,0 +1,6 @@ +// compile-flags: -g -Z src-hash-algorithm=sha1 + +#![crate_type = "lib"] + +pub fn test() {} +// CHECK: checksumkind: CSK_SHA1 diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index a221184fab029..62dc965b55f99 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -26,7 +26,6 @@ const LICENSES: &[&str] = &[ const EXCEPTIONS: &[(&str, &str)] = &[ ("mdbook", "MPL-2.0"), // mdbook ("openssl", "Apache-2.0"), // cargo, mdbook - ("arrayref", "BSD-2-Clause"), // mdbook via handlebars via pest ("toml-query", "MPL-2.0"), // mdbook ("toml-query_derive", "MPL-2.0"), // mdbook ("is-match", "MPL-2.0"), // mdbook @@ -74,6 +73,9 @@ const WHITELIST: &[&str] = &[ "backtrace", "backtrace-sys", "bitflags", + "block-buffer", + "block-padding", + "byte-tools", "byteorder", "c2-chacha", "cc", @@ -87,15 +89,18 @@ const WHITELIST: &[&str] = &[ "crossbeam-queue", "crossbeam-utils", "datafrog", + "digest", "dlmalloc", "either", "ena", "env_logger", + "fake-simd", "filetime", "flate2", "fortanix-sgx-abi", "fuchsia-zircon", "fuchsia-zircon-sys", + "generic-array", "getopts", "getrandom", "hashbrown", @@ -111,6 +116,7 @@ const WHITELIST: &[&str] = &[ "lock_api", "log", "log_settings", + "md-5", "measureme", "memchr", "memmap", @@ -118,6 +124,7 @@ const WHITELIST: &[&str] = &[ "miniz_oxide", "nodrop", "num_cpus", + "opaque-debug", "parking_lot", "parking_lot_core", "pkg-config", @@ -150,6 +157,7 @@ const WHITELIST: &[&str] = &[ "semver-parser", "serde", "serde_derive", + "sha-1", "smallvec", "stable_deref_trait", "syn", @@ -159,6 +167,7 @@ const WHITELIST: &[&str] = &[ "termion", "termize", "thread_local", + "typenum", "ucd-util", "unicode-normalization", "unicode-script",