diff --git a/configure b/configure index 597f007633640..c751ad9731a7d 100755 --- a/configure +++ b/configure @@ -649,6 +649,7 @@ opt codegen-tests 1 "run the src/test/codegen tests" opt option-checking 1 "complain about unrecognized options in this configure script" opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)" opt vendor 0 "enable usage of vendored Rust crates" +opt sanitizers 0 "build the sanitizer runtimes (asan, lsan, msan, tsan)" # Optimization and debugging options. These may be overridden by the release channel, etc. opt_nosave optimize 1 "build optimized rust code" diff --git a/mk/cfg/aarch64-unknown-freebsd.mk b/mk/cfg/aarch64-unknown-freebsd.mk deleted file mode 100644 index 34aee77ae2107..0000000000000 --- a/mk/cfg/aarch64-unknown-freebsd.mk +++ /dev/null @@ -1 +0,0 @@ -# rustbuild-only target diff --git a/mk/cfg/i686-unknown-netbsd.mk b/mk/cfg/i686-unknown-netbsd.mk deleted file mode 100644 index 34aee77ae2107..0000000000000 --- a/mk/cfg/i686-unknown-netbsd.mk +++ /dev/null @@ -1 +0,0 @@ -# rustbuild-only target diff --git a/src/Cargo.lock b/src/Cargo.lock index 53721d48d9779..09aefd45e94c8 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -277,6 +277,16 @@ name = "rustc-serialize" version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rustc_asan" +version = "0.0.0" +dependencies = [ + "alloc_system 0.0.0", + "build_helper 0.1.0", + "cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "core 0.0.0", +] + [[package]] name = "rustc_back" version = "0.0.0" @@ -410,6 +420,16 @@ dependencies = [ "rustc_bitflags 0.0.0", ] +[[package]] +name = "rustc_lsan" +version = "0.0.0" +dependencies = [ + "alloc_system 0.0.0", + "build_helper 0.1.0", + "cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "core 0.0.0", +] + [[package]] name = "rustc_metadata" version = "0.0.0" @@ -444,6 +464,16 @@ dependencies = [ "syntax_pos 0.0.0", ] +[[package]] +name = "rustc_msan" +version = "0.0.0" +dependencies = [ + "alloc_system 0.0.0", + "build_helper 0.1.0", + "cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "core 0.0.0", +] + [[package]] name = "rustc_passes" version = "0.0.0" @@ -525,6 +555,16 @@ dependencies = [ "syntax_pos 0.0.0", ] +[[package]] +name = "rustc_tsan" +version = "0.0.0" +dependencies = [ + "alloc_system 0.0.0", + "build_helper 0.1.0", + "cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "core 0.0.0", +] + [[package]] name = "rustc_typeck" version = "0.0.0" @@ -586,6 +626,10 @@ dependencies = [ "panic_abort 0.0.0", "panic_unwind 0.0.0", "rand 0.0.0", + "rustc_asan 0.0.0", + "rustc_lsan 0.0.0", + "rustc_msan 0.0.0", + "rustc_tsan 0.0.0", "std_unicode 0.0.0", "unwind 0.0.0", ] diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 0ebd105513290..cbfbcbe4f0c6e 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -242,6 +242,10 @@ pub fn compiletest(build: &Build, cmd.env("RUSTC_BOOTSTRAP", "1"); build.add_rust_test_threads(&mut cmd); + if build.config.sanitizers { + cmd.env("SANITIZER_SUPPORT", "1"); + } + cmd.arg("--adb-path").arg("adb"); cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR); if target.contains("android") { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 81dd42a1e906a..0b1a1f39d8d42 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -51,6 +51,17 @@ pub fn std(build: &Build, target: &str, compiler: &Compiler) { if compiler.stage == 0 && build.local_rebuild && !build.config.use_jemalloc { features.push_str(" force_alloc_system"); } + + if compiler.stage != 0 && build.config.sanitizers { + // This variable is used by the sanitizer runtime crates, e.g. + // rustc_lsan, to build the sanitizer runtime from C code + // When this variable is missing, those crates won't compile the C code, + // so we don't set this variable during stage0 where llvm-config is + // missing + // We also only build the runtimes when --enable-sanitizers (or its + // config.toml equivalent) is used + cargo.env("LLVM_CONFIG", build.llvm_config(target)); + } cargo.arg("--features").arg(features) .arg("--manifest-path") .arg(build.src.join("src/rustc/std_shim/Cargo.toml")); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 4e67a14345b9e..604c0397d5242 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -48,6 +48,7 @@ pub struct Config { pub target_config: HashMap, pub full_bootstrap: bool, pub extended: bool, + pub sanitizers: bool, // llvm codegen options pub llvm_assertions: bool, @@ -149,6 +150,7 @@ struct Build { python: Option, full_bootstrap: Option, extended: Option, + sanitizers: Option, } /// TOML representation of various global install decisions. @@ -294,6 +296,7 @@ impl Config { set(&mut config.vendor, build.vendor); set(&mut config.full_bootstrap, build.full_bootstrap); set(&mut config.extended, build.extended); + set(&mut config.sanitizers, build.sanitizers); if let Some(ref install) = toml.install { config.prefix = install.prefix.clone().map(PathBuf::from); @@ -438,6 +441,7 @@ impl Config { ("VENDOR", self.vendor), ("FULL_BOOTSTRAP", self.full_bootstrap), ("EXTENDED", self.extended), + ("SANITIZERS", self.sanitizers), } match key { diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index a53419ad7fd78..025fe990f91da 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -124,6 +124,9 @@ # disabled by default. #extended = false +# Build the sanitizer runtimes +#sanitizers = false + # ============================================================================= # General install configuration options # ============================================================================= diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 1c3901bf2a143..2da2892150b4f 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -515,9 +515,7 @@ pub fn cargo(build: &Build, stage: u32, target: &str) { let branch = match &build.config.channel[..] { "stable" | - "beta" => { - build.release.split(".").take(2).collect::>().join(".") - } + "beta" => format!("rust-{}", build.release_num), _ => "master".to_string(), }; diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index e58dcc9fce92f..ba6b34343f0b3 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -599,7 +599,8 @@ impl Build { /// Get the space-separated set of activated features for the standard /// library. fn std_features(&self) -> String { - let mut features = "panic-unwind".to_string(); + let mut features = "panic-unwind asan lsan msan tsan".to_string(); + if self.config.debug_jemalloc { features.push_str(" debug-jemalloc"); } diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-x86-linux/Dockerfile index 4e4f5dd6f1e53..12e24ff1af6a2 100644 --- a/src/ci/docker/dist-x86-linux/Dockerfile +++ b/src/ci/docker/dist-x86-linux/Dockerfile @@ -21,17 +21,7 @@ RUN yum upgrade -y && yum install -y \ ENV PATH=/rustroot/bin:$PATH ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib WORKDIR /tmp - -# binutils < 2.22 has a bug where the 32-bit executables it generates -# immediately segfault in Rust, so we need to install our own binutils. -# -# See https://github.com/rust-lang/rust/issues/20440 for more info COPY shared.sh build-binutils.sh /tmp/ -RUN ./build-binutils.sh - -# Need a newer version of gcc than centos has to compile LLVM nowadays -COPY build-gcc.sh /tmp/ -RUN ./build-gcc.sh # We need a build of openssl which supports SNI to download artifacts from # static.rust-lang.org. This'll be used to link into libcurl below (and used @@ -49,6 +39,16 @@ RUN ./build-openssl.sh COPY build-curl.sh /tmp/ RUN ./build-curl.sh +# binutils < 2.22 has a bug where the 32-bit executables it generates +# immediately segfault in Rust, so we need to install our own binutils. +# +# See https://github.com/rust-lang/rust/issues/20440 for more info +RUN ./build-binutils.sh + +# Need a newer version of gcc than centos has to compile LLVM nowadays +COPY build-gcc.sh /tmp/ +RUN ./build-gcc.sh + # CentOS 5.5 has Python 2.4 by default, but LLVM needs 2.7+ COPY build-python.sh /tmp/ RUN ./build-python.sh @@ -63,6 +63,11 @@ RUN ./build-git.sh COPY build-cmake.sh /tmp/ RUN ./build-cmake.sh +# for sanitizers, we need kernel headers files newer than the ones CentOS ships +# with so we install newer ones here +COPY build-headers.sh /tmp/ +RUN ./build-headers.sh + RUN curl -Lo /rustroot/dumb-init \ https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64 && \ chmod +x /rustroot/dumb-init @@ -76,5 +81,5 @@ RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | ENV HOSTS=i686-unknown-linux-gnu ENV HOSTS=$HOSTS,x86_64-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended --enable-sanitizers ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-x86-linux/build-headers.sh b/src/ci/docker/dist-x86-linux/build-headers.sh new file mode 100755 index 0000000000000..4ce38fd9205e2 --- /dev/null +++ b/src/ci/docker/dist-x86-linux/build-headers.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x + +cd linux-3.2.84 +hide_output make mrproper +hide_output make INSTALL_HDR_PATH=dest headers_install + +find dest/include \( -name .install -o -name ..install.cmd \) -delete +yes | cp -fr dest/include/* /usr/include + +cd .. +rm -rf linux-3.2.84 diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile index 6919487e17c3e..e903b6ddc64cd 100644 --- a/src/ci/docker/x86_64-gnu/Dockerfile +++ b/src/ci/docker/x86_64-gnu/Dockerfile @@ -22,5 +22,5 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini rm dumb-init_*.deb ENTRYPOINT ["/usr/bin/dumb-init", "--"] -ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --enable-sanitizers ENV SCRIPT python2.7 ../x.py test && python2.7 ../x.py dist diff --git a/src/compiler-rt b/src/compiler-rt index a8fc4c169fac4..d30da544a8afc 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178 +Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3 diff --git a/src/doc/reference.md b/src/doc/reference.md index f9013490418f3..8aefabe61fdf6 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1291,15 +1291,18 @@ guaranteed to refer to the same memory address. Constant values must not have destructors, and otherwise permit most forms of data. Constants may refer to the address of other constants, in which case the -address will have the `static` lifetime. The compiler is, however, still at -liberty to translate the constant many times, so the address referred to may not -be stable. +address will have elided lifetimes where applicable, otherwise – in most cases – +defaulting to the `static` lifetime. (See below on [static lifetime elision].) +The compiler is, however, still at liberty to translate the constant many times, +so the address referred to may not be stable. + +[static lifetime elision]: #static-lifetime-elision Constants must be explicitly typed. The type may be `bool`, `char`, a number, or a type derived from those primitive types. The derived types are references with the `static` lifetime, fixed-size arrays, tuples, enum variants, and structs. -``` +```rust const BIT1: u32 = 1 << 0; const BIT2: u32 = 1 << 1; @@ -1317,6 +1320,8 @@ const BITS_N_STRINGS: BitsNStrings<'static> = BitsNStrings { }; ``` + + ### Static items A *static item* is similar to a *constant*, except that it represents a precise @@ -1351,7 +1356,7 @@ running in the same process. Mutable statics are still very useful, however. They can be used with C libraries and can also be bound from C libraries (in an `extern` block). -``` +```rust # fn atomic_add(_: &mut u32, _: u32) -> u32 { 2 } static mut LEVELS: u32 = 0; @@ -1375,6 +1380,53 @@ unsafe fn bump_levels_unsafe2() -> u32 { Mutable statics have the same restrictions as normal statics, except that the type of the value is not required to ascribe to `Sync`. +#### `'static` lifetime elision + +[Unstable] Both constant and static declarations of reference types have +*implicit* `'static` lifetimes unless an explicit lifetime is specified. As +such, the constant declarations involving `'static` above may be written +without the lifetimes. Returning to our previous example: + +```rust +# #![feature(static_in_const)] +const BIT1: u32 = 1 << 0; +const BIT2: u32 = 1 << 1; + +const BITS: [u32; 2] = [BIT1, BIT2]; +const STRING: &str = "bitstring"; + +struct BitsNStrings<'a> { + mybits: [u32; 2], + mystring: &'a str, +} + +const BITS_N_STRINGS: BitsNStrings = BitsNStrings { + mybits: BITS, + mystring: STRING, +}; +``` + +Note that if the `static` or `const` items include function or closure +references, which themselves include references, the compiler will first try the +standard elision rules ([see discussion in the nomicon][elision-nomicon]). If it +is unable to resolve the lifetimes by its usual rules, it will default to using +the `'static` lifetime. By way of example: + +[elision-nomicon]: https://doc.rust-lang.org/nomicon/lifetime-elision.html + +```rust,ignore +// Resolved as `fn<'a>(&'a str) -> &'a str`. +const RESOLVED_SINGLE: fn(&str) -> &str = .. + +// Resolved as `Fn<'a, 'b, 'c>(&'a Foo, &'b Bar, &'c Baz) -> usize`. +const RESOLVED_MULTIPLE: Fn(&Foo, &Bar, &Baz) -> usize = .. + +// There is insufficient information to bound the return reference lifetime +// relative to the argument lifetimes, so the signature is resolved as +// `Fn(&'static Foo, &'static Bar) -> &'static Baz`. +const RESOLVED_STATIC: Fn(&Foo, &Bar) -> &Baz = .. +``` + ### Traits A _trait_ describes an abstract interface that types can @@ -2072,7 +2124,9 @@ macro scope. ### Miscellaneous attributes -- `deprecated` - mark the item as deprecated; the full attribute is `#[deprecated(since = "crate version", note = "...")`, where both arguments are optional. +- `deprecated` - mark the item as deprecated; the full attribute is + `#[deprecated(since = "crate version", note = "...")`, where both arguments + are optional. - `export_name` - on statics and functions, this determines the name of the exported symbol. - `link_section` - on statics and functions, this specifies the section of the @@ -2489,9 +2543,6 @@ The currently implemented features of the reference compiler are: into a Rust program. This capability, especially the signature for the annotated function, is subject to change. -* `static_in_const` - Enables lifetime elision with a `'static` default for - `const` and `static` item declarations. - * `thread_local` - The usage of the `#[thread_local]` attribute is experimental and should be seen as unstable. This attribute is used to declare a `static` as being unique per-thread leveraging diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 6537cc1adce00..2d80fc32c469d 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -229,6 +229,7 @@ pub trait CrateStore<'tcx> { fn is_allocator(&self, cnum: CrateNum) -> bool; fn is_panic_runtime(&self, cnum: CrateNum) -> bool; fn is_compiler_builtins(&self, cnum: CrateNum) -> bool; + fn is_sanitizer_runtime(&self, cnum: CrateNum) -> bool; fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy; fn extern_crate(&self, cnum: CrateNum) -> Option; /// The name of the crate as it is referred to in source code of the current @@ -390,6 +391,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn is_allocator(&self, cnum: CrateNum) -> bool { bug!("is_allocator") } fn is_panic_runtime(&self, cnum: CrateNum) -> bool { bug!("is_panic_runtime") } fn is_compiler_builtins(&self, cnum: CrateNum) -> bool { bug!("is_compiler_builtins") } + fn is_sanitizer_runtime(&self, cnum: CrateNum) -> bool { bug!("is_sanitizer_runtime") } fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy { bug!("panic_strategy") } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index d41c2ba93b935..24615f2fa6992 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -51,6 +51,14 @@ pub struct Config { pub uint_type: UintTy, } +#[derive(Clone)] +pub enum Sanitizer { + Address, + Leak, + Memory, + Thread, +} + #[derive(Clone, Copy, PartialEq, Hash)] pub enum OptLevel { No, // -O0 @@ -626,11 +634,13 @@ macro_rules! options { Some("a number"); pub const parse_panic_strategy: Option<&'static str> = Some("either `panic` or `abort`"); + pub const parse_sanitizer: Option<&'static str> = + Some("one of: `address`, `leak`, `memory` or `thread`"); } #[allow(dead_code)] mod $mod_set { - use super::{$struct_name, Passes, SomePasses, AllPasses}; + use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer}; use rustc_back::PanicStrategy; $( @@ -751,6 +761,17 @@ macro_rules! options { } true } + + fn parse_sanitizer(slote: &mut Option, v: Option<&str>) -> bool { + match v { + Some("address") => *slote = Some(Sanitizer::Address), + Some("leak") => *slote = Some(Sanitizer::Leak), + Some("memory") => *slote = Some(Sanitizer::Memory), + Some("thread") => *slote = Some(Sanitizer::Thread), + _ => return false, + } + true + } } ) } @@ -949,6 +970,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "encode MIR of all functions into the crate metadata"), osx_rpath_install_name: bool = (false, parse_bool, [TRACKED], "pass `-install_name @rpath/...` to the OSX linker"), + sanitizer: Option = (None, parse_sanitizer, [UNTRACKED], + "Use a sanitizer"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc_asan/Cargo.toml b/src/librustc_asan/Cargo.toml new file mode 100644 index 0000000000000..2d4872b1fc942 --- /dev/null +++ b/src/librustc_asan/Cargo.toml @@ -0,0 +1,17 @@ +[package] +authors = ["The Rust Project Developers"] +build = "build.rs" +name = "rustc_asan" +version = "0.0.0" + +[lib] +name = "rustc_asan" +path = "lib.rs" + +[build-dependencies] +build_helper = { path = "../build_helper" } +cmake = "0.1.18" + +[dependencies] +alloc_system = { path = "../liballoc_system" } +core = { path = "../libcore" } diff --git a/src/librustc_asan/build.rs b/src/librustc_asan/build.rs new file mode 100644 index 0000000000000..015be14bd495a --- /dev/null +++ b/src/librustc_asan/build.rs @@ -0,0 +1,39 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate build_helper; +extern crate cmake; + +use std::path::PathBuf; +use std::env; + +use cmake::Config; + +fn main() { + if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { + let dst = Config::new("../compiler-rt") + .define("COMPILER_RT_BUILD_SANITIZERS", "ON") + .define("COMPILER_RT_BUILD_BUILTINS", "OFF") + .define("COMPILER_RT_BUILD_XRAY", "OFF") + .define("LLVM_CONFIG_PATH", llvm_config) + .build_target("asan") + .build(); + + println!("cargo:rustc-link-search=native={}", + dst.join("build/lib/linux").display()); + println!("cargo:rustc-link-lib=static=clang_rt.asan-x86_64"); + + build_helper::rerun_if_changed_anything_in_dir(&PathBuf::from(env::var("CARGO_MANIFEST_DIR") + .unwrap()) + .join("../compiler-rt")); + } + + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs new file mode 100644 index 0000000000000..71a166b91ebcb --- /dev/null +++ b/src/librustc_asan/lib.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg_attr(not(stage0), feature(sanitizer_runtime))] +#![cfg_attr(not(stage0), sanitizer_runtime)] +#![feature(alloc_system)] +#![feature(staged_api)] +#![no_std] +#![unstable(feature = "sanitizer_runtime_lib", + reason = "internal implementation detail of sanitizers", + issue = "0")] + +extern crate alloc_system; diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 07d36448ab0f8..949e949f673a2 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -126,6 +126,9 @@ pub enum Attribute { UWTable = 17, ZExt = 18, InReg = 19, + SanitizeThread = 20, + SanitizeAddress = 21, + SanitizeMemory = 22, } /// LLVMIntPredicate diff --git a/src/librustc_lsan/Cargo.toml b/src/librustc_lsan/Cargo.toml new file mode 100644 index 0000000000000..bc1f2ead76884 --- /dev/null +++ b/src/librustc_lsan/Cargo.toml @@ -0,0 +1,17 @@ +[package] +authors = ["The Rust Project Developers"] +build = "build.rs" +name = "rustc_lsan" +version = "0.0.0" + +[lib] +name = "rustc_lsan" +path = "lib.rs" + +[build-dependencies] +build_helper = { path = "../build_helper" } +cmake = "0.1.18" + +[dependencies] +alloc_system = { path = "../liballoc_system" } +core = { path = "../libcore" } diff --git a/src/librustc_lsan/build.rs b/src/librustc_lsan/build.rs new file mode 100644 index 0000000000000..5773777d1f81b --- /dev/null +++ b/src/librustc_lsan/build.rs @@ -0,0 +1,39 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate build_helper; +extern crate cmake; + +use std::path::PathBuf; +use std::env; + +use cmake::Config; + +fn main() { + if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { + let dst = Config::new("../compiler-rt") + .define("COMPILER_RT_BUILD_SANITIZERS", "ON") + .define("COMPILER_RT_BUILD_BUILTINS", "OFF") + .define("COMPILER_RT_BUILD_XRAY", "OFF") + .define("LLVM_CONFIG_PATH", llvm_config) + .build_target("lsan") + .build(); + + println!("cargo:rustc-link-search=native={}", + dst.join("build/lib/linux").display()); + println!("cargo:rustc-link-lib=static=clang_rt.lsan-x86_64"); + + build_helper::rerun_if_changed_anything_in_dir(&PathBuf::from(env::var("CARGO_MANIFEST_DIR") + .unwrap()) + .join("../compiler-rt")); + } + + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/src/librustc_lsan/lib.rs b/src/librustc_lsan/lib.rs new file mode 100644 index 0000000000000..71a166b91ebcb --- /dev/null +++ b/src/librustc_lsan/lib.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg_attr(not(stage0), feature(sanitizer_runtime))] +#![cfg_attr(not(stage0), sanitizer_runtime)] +#![feature(alloc_system)] +#![feature(staged_api)] +#![no_std] +#![unstable(feature = "sanitizer_runtime_lib", + reason = "internal implementation detail of sanitizers", + issue = "0")] + +extern crate alloc_system; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 81a4f7c93b6e9..55dc5aa2876f6 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -17,7 +17,8 @@ use schema::CrateRoot; use rustc::hir::def_id::{CrateNum, DefIndex}; use rustc::hir::svh::Svh; use rustc::middle::cstore::DepKind; -use rustc::session::{config, Session}; +use rustc::session::Session; +use rustc::session::config::{Sanitizer, self}; use rustc_back::PanicStrategy; use rustc::session::search_paths::PathKind; use rustc::middle; @@ -786,6 +787,64 @@ impl<'a> CrateLoader<'a> { &|data| data.needs_panic_runtime()); } + fn inject_sanitizer_runtime(&mut self) { + if let Some(ref sanitizer) = self.sess.opts.debugging_opts.sanitizer { + // Sanitizers can only be used with x86_64 Linux executables linked + // to `std` + if self.sess.target.target.llvm_target != "x86_64-unknown-linux-gnu" { + self.sess.err(&format!("Sanitizers only work with the \ + `x86_64-unknown-linux-gnu` target.")); + return + } + + if !self.sess.crate_types.borrow().iter().all(|ct| { + match *ct { + // Link the runtime + config::CrateTypeExecutable => true, + // This crate will be compiled with the required + // instrumentation pass + config::CrateTypeRlib => false, + _ => { + self.sess.err(&format!("Only executables and rlibs can be \ + compiled with `-Z sanitizer`")); + false + } + } + }) { + return + } + + let mut uses_std = false; + self.cstore.iter_crate_data(|_, data| { + if data.name == "std" { + uses_std = true; + } + }); + + if uses_std { + let name = match *sanitizer { + Sanitizer::Address => "rustc_asan", + Sanitizer::Leak => "rustc_lsan", + Sanitizer::Memory => "rustc_msan", + Sanitizer::Thread => "rustc_tsan", + }; + info!("loading sanitizer: {}", name); + + let symbol = Symbol::intern(name); + let dep_kind = DepKind::Implicit; + let (_, data) = + self.resolve_crate(&None, symbol, symbol, None, DUMMY_SP, + PathKind::Crate, dep_kind); + + // Sanity check the loaded crate to ensure it is indeed a sanitizer runtime + if !data.is_sanitizer_runtime() { + self.sess.err(&format!("the crate `{}` is not a sanitizer runtime", + name)); + } + } + } + } + fn inject_allocator_crate(&mut self) { // Make sure that we actually need an allocator, if none of our // dependencies need one then we definitely don't! @@ -982,6 +1041,9 @@ impl<'a> CrateLoader<'a> { impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { fn postprocess(&mut self, krate: &ast::Crate) { + // inject the sanitizer runtime before the allocator runtime because all + // sanitizers force the use of the `alloc_system` allocator + self.inject_sanitizer_runtime(); self.inject_allocator_crate(); self.inject_panic_runtime(krate); diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index beba5faf3d034..4709ca6101c79 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -297,6 +297,11 @@ impl CrateMetadata { attr::contains_name(&attrs, "compiler_builtins") } + pub fn is_sanitizer_runtime(&self) -> bool { + let attrs = self.get_item_attrs(CRATE_DEF_INDEX); + attr::contains_name(&attrs, "sanitizer_runtime") + } + pub fn is_no_builtins(&self) -> bool { let attrs = self.get_item_attrs(CRATE_DEF_INDEX); attr::contains_name(&attrs, "no_builtins") diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 39581a4696088..7b0177bfd23ed 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -297,6 +297,10 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(cnum).is_compiler_builtins() } + fn is_sanitizer_runtime(&self, cnum: CrateNum) -> bool { + self.get_crate_data(cnum).is_sanitizer_runtime() + } + fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy { self.get_crate_data(cnum).panic_strategy() } diff --git a/src/librustc_msan/Cargo.toml b/src/librustc_msan/Cargo.toml new file mode 100644 index 0000000000000..45cc6b9839fb8 --- /dev/null +++ b/src/librustc_msan/Cargo.toml @@ -0,0 +1,17 @@ +[package] +authors = ["The Rust Project Developers"] +build = "build.rs" +name = "rustc_msan" +version = "0.0.0" + +[lib] +name = "rustc_msan" +path = "lib.rs" + +[build-dependencies] +build_helper = { path = "../build_helper" } +cmake = "0.1.18" + +[dependencies] +alloc_system = { path = "../liballoc_system" } +core = { path = "../libcore" } diff --git a/src/librustc_msan/build.rs b/src/librustc_msan/build.rs new file mode 100644 index 0000000000000..7a4c8f7073933 --- /dev/null +++ b/src/librustc_msan/build.rs @@ -0,0 +1,39 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate build_helper; +extern crate cmake; + +use std::path::PathBuf; +use std::env; + +use cmake::Config; + +fn main() { + if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { + let dst = Config::new("../compiler-rt") + .define("COMPILER_RT_BUILD_SANITIZERS", "ON") + .define("COMPILER_RT_BUILD_BUILTINS", "OFF") + .define("COMPILER_RT_BUILD_XRAY", "OFF") + .define("LLVM_CONFIG_PATH", llvm_config) + .build_target("msan") + .build(); + + println!("cargo:rustc-link-search=native={}", + dst.join("build/lib/linux").display()); + println!("cargo:rustc-link-lib=static=clang_rt.msan-x86_64"); + + build_helper::rerun_if_changed_anything_in_dir(&PathBuf::from(env::var("CARGO_MANIFEST_DIR") + .unwrap()) + .join("../compiler-rt")); + } + + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/src/librustc_msan/lib.rs b/src/librustc_msan/lib.rs new file mode 100644 index 0000000000000..71a166b91ebcb --- /dev/null +++ b/src/librustc_msan/lib.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg_attr(not(stage0), feature(sanitizer_runtime))] +#![cfg_attr(not(stage0), sanitizer_runtime)] +#![feature(alloc_system)] +#![feature(staged_api)] +#![no_std] +#![unstable(feature = "sanitizer_runtime_lib", + reason = "internal implementation detail of sanitizers", + issue = "0")] + +extern crate alloc_system; diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 4ddf8a883bc48..1cbfa26b705ac 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -1031,6 +1031,9 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // symbols from the dylib. let src = sess.cstore.used_crate_source(cnum); match data[cnum.as_usize() - 1] { + _ if sess.cstore.is_sanitizer_runtime(cnum) => { + link_sanitizer_runtime(cmd, sess, tmpdir, cnum); + } // compiler-builtins are always placed last to ensure that they're // linked correctly. _ if sess.cstore.is_compiler_builtins(cnum) => { @@ -1048,6 +1051,8 @@ fn add_upstream_rust_crates(cmd: &mut Linker, } } + // compiler-builtins are always placed last to ensure that they're + // linked correctly. // We must always link the `compiler_builtins` crate statically. Even if it // was already "included" in a dylib (e.g. `libstd` when `-C prefer-dynamic` // is used) @@ -1064,6 +1069,34 @@ fn add_upstream_rust_crates(cmd: &mut Linker, } } + // We must link the sanitizer runtime using -Wl,--whole-archive but since + // it's packed in a .rlib, it contains stuff that are not objects that will + // make the linker error. So we must remove those bits from the .rlib before + // linking it. + fn link_sanitizer_runtime(cmd: &mut Linker, + sess: &Session, + tmpdir: &Path, + cnum: CrateNum) { + let src = sess.cstore.used_crate_source(cnum); + let cratepath = &src.rlib.unwrap().0; + let dst = tmpdir.join(cratepath.file_name().unwrap()); + let cfg = archive_config(sess, &dst, Some(cratepath)); + let mut archive = ArchiveBuilder::new(cfg); + archive.update_symbols(); + + for f in archive.src_files() { + if f.ends_with("bytecode.deflate") || + f == sess.cstore.metadata_filename() { + archive.remove_file(&f); + continue + } + } + + archive.build(); + + cmd.link_whole_rlib(&dst); + } + // Adds the static "rlib" versions of all crates to the command line. // There's a bit of magic which happens here specifically related to LTO and // dynamic libraries. Specifically: diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 9a761e17e75e8..5c4a5a9a4423d 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -12,7 +12,7 @@ use back::lto; use back::link::{get_linker, remove}; use back::symbol_export::ExportedSymbols; use rustc_incremental::{save_trans_partition, in_incr_comp_dir}; -use session::config::{OutputFilenames, OutputTypes, Passes, SomePasses, AllPasses}; +use session::config::{OutputFilenames, OutputTypes, Passes, SomePasses, AllPasses, Sanitizer}; use session::Session; use session::config::{self, OutputType}; use llvm; @@ -679,6 +679,22 @@ pub fn run_passes(sess: &Session, let mut modules_config = ModuleConfig::new(tm, sess.opts.cg.passes.clone()); let mut metadata_config = ModuleConfig::new(tm, vec![]); + if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer { + match *sanitizer { + Sanitizer::Address => { + modules_config.passes.push("asan".to_owned()); + modules_config.passes.push("asan-module".to_owned()); + } + Sanitizer::Memory => { + modules_config.passes.push("msan".to_owned()) + } + Sanitizer::Thread => { + modules_config.passes.push("tsan".to_owned()) + } + _ => {} + } + } + modules_config.opt_level = Some(get_llvm_opt_level(sess.opts.optimize)); modules_config.opt_size = Some(get_llvm_opt_size(sess.opts.optimize)); diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index bf7a02eb0f196..7ac482459ee39 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -23,6 +23,7 @@ use llvm::{self, ValueRef}; use llvm::AttributePlace::Function; use rustc::ty; +use rustc::session::config::Sanitizer; use abi::{Abi, FnType}; use attributes; use context::CrateContext; @@ -72,6 +73,21 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: llvm::Attribute::NoRedZone.apply_llfn(Function, llfn); } + if let Some(ref sanitizer) = ccx.tcx().sess.opts.debugging_opts.sanitizer { + match *sanitizer { + Sanitizer::Address => { + llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn); + }, + Sanitizer::Memory => { + llvm::Attribute::SanitizeMemory.apply_llfn(Function, llfn); + }, + Sanitizer::Thread => { + llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn); + }, + _ => {} + } + } + // If we're compiling the compiler-builtins crate, e.g. the equivalent of // compiler-rt, then we want to implicitly compile everything with hidden // visibility as we're going to link this object all over the place but diff --git a/src/librustc_tsan/Cargo.toml b/src/librustc_tsan/Cargo.toml new file mode 100644 index 0000000000000..66d6236361ea2 --- /dev/null +++ b/src/librustc_tsan/Cargo.toml @@ -0,0 +1,17 @@ +[package] +authors = ["The Rust Project Developers"] +build = "build.rs" +name = "rustc_tsan" +version = "0.0.0" + +[lib] +name = "rustc_tsan" +path = "lib.rs" + +[build-dependencies] +build_helper = { path = "../build_helper" } +cmake = "0.1.18" + +[dependencies] +alloc_system = { path = "../liballoc_system" } +core = { path = "../libcore" } diff --git a/src/librustc_tsan/build.rs b/src/librustc_tsan/build.rs new file mode 100644 index 0000000000000..84326ae8a7106 --- /dev/null +++ b/src/librustc_tsan/build.rs @@ -0,0 +1,39 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate build_helper; +extern crate cmake; + +use std::path::PathBuf; +use std::env; + +use cmake::Config; + +fn main() { + if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { + let dst = Config::new("../compiler-rt") + .define("COMPILER_RT_BUILD_SANITIZERS", "ON") + .define("COMPILER_RT_BUILD_BUILTINS", "OFF") + .define("COMPILER_RT_BUILD_XRAY", "OFF") + .define("LLVM_CONFIG_PATH", llvm_config) + .build_target("tsan") + .build(); + + println!("cargo:rustc-link-search=native={}", + dst.join("build/lib/linux").display()); + println!("cargo:rustc-link-lib=static=clang_rt.tsan-x86_64"); + + build_helper::rerun_if_changed_anything_in_dir(&PathBuf::from(env::var("CARGO_MANIFEST_DIR") + .unwrap()) + .join("../compiler-rt")); + } + + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/src/librustc_tsan/lib.rs b/src/librustc_tsan/lib.rs new file mode 100644 index 0000000000000..71a166b91ebcb --- /dev/null +++ b/src/librustc_tsan/lib.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg_attr(not(stage0), feature(sanitizer_runtime))] +#![cfg_attr(not(stage0), sanitizer_runtime)] +#![feature(alloc_system)] +#![feature(staged_api)] +#![no_std] +#![unstable(feature = "sanitizer_runtime_lib", + reason = "internal implementation detail of sanitizers", + issue = "0")] + +extern crate alloc_system; diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 60dae19d876c9..c591c09bf20e2 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -671,9 +671,11 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt: } _ => { if f.alternate() { - write!(f, "&{}{}{:#}", lt, m, **ty) + write!(f, "&{}{}", lt, m)?; + fmt_type(&ty, f, use_absolute) } else { - write!(f, "&{}{}{}", lt, m, **ty) + write!(f, "&{}{}", lt, m)?; + fmt_type(&ty, f, use_absolute) } } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 40eb7e5ab78c3..6234d89024441 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2132,10 +2132,23 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
    ")?; if let Some(implementors) = cache.implementors.get(&it.def_id) { - let mut implementor_count: FxHashMap<&str, usize> = FxHashMap(); + // The DefId is for the first Type found with that name. The bool is + // if any Types with the same name but different DefId have been found. + let mut implementor_dups: FxHashMap<&str, (DefId, bool)> = FxHashMap(); for implementor in implementors { - if let clean::Type::ResolvedPath {ref path, ..} = implementor.impl_.for_ { - *implementor_count.entry(path.last_name()).or_insert(0) += 1; + match implementor.impl_.for_ { + clean::ResolvedPath { ref path, did, is_generic: false, .. } | + clean::BorrowedRef { + type_: box clean::ResolvedPath { ref path, did, is_generic: false, .. }, + .. + } => { + let &mut (prev_did, ref mut has_duplicates) = + implementor_dups.entry(path.last_name()).or_insert((did, false)); + if prev_did != did { + *has_duplicates = true; + } + } + _ => {} } } @@ -2143,12 +2156,13 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, write!(w, "
  • ")?; // If there's already another implementor that has the same abbridged name, use the // full path, for example in `std::iter::ExactSizeIterator` - let use_absolute = if let clean::Type::ResolvedPath { - ref path, .. - } = implementor.impl_.for_ { - implementor_count[path.last_name()] > 1 - } else { - false + let use_absolute = match implementor.impl_.for_ { + clean::ResolvedPath { ref path, is_generic: false, .. } | + clean::BorrowedRef { + type_: box clean::ResolvedPath { ref path, is_generic: false, .. }, + .. + } => implementor_dups[path.last_name()].1, + _ => false, }; fmt_impl_for_trait_page(&implementor.impl_, w, use_absolute)?; writeln!(w, "
  • ")?; diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 8146e7fb1edaf..2ba7517d3d202 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -23,13 +23,23 @@ compiler_builtins = { path = "../libcompiler_builtins" } std_unicode = { path = "../libstd_unicode" } unwind = { path = "../libunwind" } +[target.x86_64-unknown-linux-gnu.dependencies] +rustc_asan = { path = "../librustc_asan", optional = true } +rustc_lsan = { path = "../librustc_lsan", optional = true } +rustc_msan = { path = "../librustc_msan", optional = true } +rustc_tsan = { path = "../librustc_tsan", optional = true } + [build-dependencies] build_helper = { path = "../build_helper" } gcc = "0.3.27" [features] +asan = ["rustc_asan"] backtrace = [] debug-jemalloc = ["alloc_jemalloc/debug"] jemalloc = ["alloc_jemalloc"] force_alloc_system = [] +lsan = ["rustc_lsan"] +msan = ["rustc_msan"] panic-unwind = ["panic_unwind"] +tsan = ["rustc_tsan"] diff --git a/src/libstd/env.rs b/src/libstd/env.rs index e264153929491..1ef2cb4ed153c 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -400,15 +400,19 @@ pub struct JoinPathsError { inner: os_imp::JoinPathsError } -/// Joins a collection of `Path`s appropriately for the `PATH` +/// Joins a collection of [`Path`]s appropriately for the `PATH` /// environment variable. /// -/// Returns an `OsString` on success. +/// Returns an [`OsString`] on success. /// -/// Returns an `Err` (containing an error message) if one of the input -/// `Path`s contains an invalid character for constructing the `PATH` +/// Returns an [`Err`][err] (containing an error message) if one of the input +/// [`Path`]s contains an invalid character for constructing the `PATH` /// variable (a double quote on Windows or a colon on Unix). /// +/// [`Path`]: ../../std/path/struct.Path.html +/// [`OsString`]: ../../std/ffi/struct.OsString.html +/// [err]: ../../std/result/enum.Result.html#variant.Err +/// /// # Examples /// /// ``` diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index a78c192a120df..cc0a67b3d2e94 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -328,6 +328,10 @@ declare_features! ( // `extern "msp430-interrupt" fn()` (active, abi_msp430_interrupt, "1.16.0", Some(38487)), + + // Used to identify crates that contain sanitizer runtimes + // rustc internal + (active, sanitizer_runtime, "1.17.0", None), ); declare_features! ( @@ -647,6 +651,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG contains compiler-rt intrinsics and will never be \ stable", cfg_fn!(compiler_builtins))), + ("sanitizer_runtime", Whitelisted, Gated(Stability::Unstable, + "sanitizer_runtime", + "the `#[sanitizer_runtime]` attribute is used to \ + identify crates that contain the runtime of a \ + sanitizer and will never be stable", + cfg_fn!(sanitizer_runtime))), ("allow_internal_unstable", Normal, Gated(Stability::Unstable, "allow_internal_unstable", diff --git a/src/rustc/std_shim/Cargo.toml b/src/rustc/std_shim/Cargo.toml index 14c9c5544b188..db96079d3e916 100644 --- a/src/rustc/std_shim/Cargo.toml +++ b/src/rustc/std_shim/Cargo.toml @@ -35,8 +35,12 @@ core = { path = "../../libcore" } # Reexport features from std [features] +asan = ["std/asan"] backtrace = ["std/backtrace"] debug-jemalloc = ["std/debug-jemalloc"] jemalloc = ["std/jemalloc"] force_alloc_system = ["std/force_alloc_system"] +lsan = ["std/lsan"] +msan = ["std/msan"] panic-unwind = ["std/panic-unwind"] +tsan = ["std/tsan"] diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 4e201c254e39f..f3b52b71b99c1 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -148,6 +148,12 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { return Attribute::ZExt; case InReg: return Attribute::InReg; + case SanitizeThread: + return Attribute::SanitizeThread; + case SanitizeAddress: + return Attribute::SanitizeAddress; + case SanitizeMemory: + return Attribute::SanitizeMemory; } llvm_unreachable("bad AttributeKind"); } diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h index a30fa3133e282..0baf5528e9356 100644 --- a/src/rustllvm/rustllvm.h +++ b/src/rustllvm/rustllvm.h @@ -98,6 +98,9 @@ enum LLVMRustAttribute { UWTable = 17, ZExt = 18, InReg = 19, + SanitizeThread = 20, + SanitizeAddress = 21, + SanitizeMemory = 22, }; typedef struct OpaqueRustString *RustStringRef; diff --git a/src/test/compile-fail/feature-gate-sanitizer-runtime.rs b/src/test/compile-fail/feature-gate-sanitizer-runtime.rs new file mode 100644 index 0000000000000..a18641d824691 --- /dev/null +++ b/src/test/compile-fail/feature-gate-sanitizer-runtime.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![sanitizer_runtime] //~ ERROR the `#[sanitizer_runtime]` attribute is + +fn main() {} diff --git a/src/test/compile-fail/issue-27433.rs b/src/test/compile-fail/issue-27433.rs new file mode 100644 index 0000000000000..78d96398b9587 --- /dev/null +++ b/src/test/compile-fail/issue-27433.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let foo = 42u32; + const FOO : u32 = foo; + //~^ ERROR attempt to use a non-constant value in a constant +} diff --git a/src/test/run-make/sanitizer-address/Makefile b/src/test/run-make/sanitizer-address/Makefile new file mode 100644 index 0000000000000..5931145f3a47d --- /dev/null +++ b/src/test/run-make/sanitizer-address/Makefile @@ -0,0 +1,11 @@ +-include ../tools.mk + +# NOTE the address sanitizer only supports x86_64 linux +ifdef SANITIZER_SUPPORT +all: + $(RUSTC) -g -Z sanitizer=address -Z print-link-args overflow.rs | grep -q librustc_asan + $(TMPDIR)/overflow 2>&1 | grep -q stack-buffer-overflow +else +all: + +endif diff --git a/src/test/run-make/sanitizer-address/overflow.rs b/src/test/run-make/sanitizer-address/overflow.rs new file mode 100644 index 0000000000000..e35c3873f7eb5 --- /dev/null +++ b/src/test/run-make/sanitizer-address/overflow.rs @@ -0,0 +1,14 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let xs = [0, 1, 2, 3]; + let y = unsafe { *xs.as_ptr().offset(4) }; +} diff --git a/src/test/run-make/sanitizer-dylib/Makefile b/src/test/run-make/sanitizer-dylib/Makefile new file mode 100644 index 0000000000000..835d5b0d9d8cd --- /dev/null +++ b/src/test/run-make/sanitizer-dylib/Makefile @@ -0,0 +1,8 @@ +-include ../tools.mk + +ifeq ($(TARGET),x86_64-unknown-linux-gnu) +all: + $(RUSTC) -Z sanitizer=leak --crate-type dylib --target $(TARGET) hello.rs 2>&1 | grep -q 'Only executables and rlibs can be compiled with `-Z sanitizer`' +else +all: +endif diff --git a/src/test/run-make/sanitizer-dylib/hello.rs b/src/test/run-make/sanitizer-dylib/hello.rs new file mode 100644 index 0000000000000..41782851a1a6d --- /dev/null +++ b/src/test/run-make/sanitizer-dylib/hello.rs @@ -0,0 +1,13 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + println!("Hello, world!"); +} diff --git a/src/test/run-make/sanitizer-invalid-target/Makefile b/src/test/run-make/sanitizer-invalid-target/Makefile new file mode 100644 index 0000000000000..6a1ce8bab2fb6 --- /dev/null +++ b/src/test/run-make/sanitizer-invalid-target/Makefile @@ -0,0 +1,4 @@ +-include ../tools.mk + +all: + $(RUSTC) -Z sanitizer=leak --target i686-unknown-linux-gnu hello.rs 2>&1 | grep -q 'Sanitizers only work with the `x86_64-unknown-linux-gnu` target' diff --git a/src/test/run-make/sanitizer-invalid-target/hello.rs b/src/test/run-make/sanitizer-invalid-target/hello.rs new file mode 100644 index 0000000000000..e9e46b7702a80 --- /dev/null +++ b/src/test/run-make/sanitizer-invalid-target/hello.rs @@ -0,0 +1,13 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(no_core)] +#![no_core] +#![no_main] diff --git a/src/test/run-make/sanitizer-leak/Makefile b/src/test/run-make/sanitizer-leak/Makefile new file mode 100644 index 0000000000000..f02d948fdc84f --- /dev/null +++ b/src/test/run-make/sanitizer-leak/Makefile @@ -0,0 +1,10 @@ +-include ../tools.mk + +ifdef SANITIZER_SUPPORT +all: + $(RUSTC) -C opt-level=1 -g -Z sanitizer=leak -Z print-link-args leak.rs | grep -q librustc_lsan + $(TMPDIR)/leak 2>&1 | grep -q 'detected memory leaks' +else +all: + +endif diff --git a/src/test/run-make/sanitizer-leak/leak.rs b/src/test/run-make/sanitizer-leak/leak.rs new file mode 100644 index 0000000000000..279da6aaae707 --- /dev/null +++ b/src/test/run-make/sanitizer-leak/leak.rs @@ -0,0 +1,16 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem; + +fn main() { + let xs = vec![1, 2, 3, 4]; + mem::forget(xs); +} diff --git a/src/test/run-make/sanitizer-memory/Makefile b/src/test/run-make/sanitizer-memory/Makefile new file mode 100644 index 0000000000000..08682e5975e51 --- /dev/null +++ b/src/test/run-make/sanitizer-memory/Makefile @@ -0,0 +1,10 @@ +-include ../tools.mk + +ifdef SANITIZER_SUPPORT +all: + $(RUSTC) -g -Z sanitizer=memory -Z print-link-args uninit.rs | grep -q librustc_msan + $(TMPDIR)/uninit 2>&1 | grep -q use-of-uninitialized-value +else +all: + +endif diff --git a/src/test/run-make/sanitizer-memory/uninit.rs b/src/test/run-make/sanitizer-memory/uninit.rs new file mode 100644 index 0000000000000..8350c7de3acab --- /dev/null +++ b/src/test/run-make/sanitizer-memory/uninit.rs @@ -0,0 +1,16 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem; + +fn main() { + let xs: [u8; 4] = unsafe { mem::uninitialized() }; + let y = xs[0] + xs[1]; +} diff --git a/src/test/run-make/sanitizer-thread/Makefile b/src/test/run-make/sanitizer-thread/Makefile new file mode 100644 index 0000000000000..8bb89a241cb05 --- /dev/null +++ b/src/test/run-make/sanitizer-thread/Makefile @@ -0,0 +1,10 @@ +-include ../tools.mk + +ifdef SANITIZER_SUPPORT +all: + $(RUSTC) -g -Z sanitizer=thread -Z print-link-args racy.rs | grep -q librustc_tsan + $(TMPDIR)/racy 2>&1 | grep -q 'data race' +else +all: + +endif diff --git a/src/test/run-make/sanitizer-thread/racy.rs b/src/test/run-make/sanitizer-thread/racy.rs new file mode 100644 index 0000000000000..dc929e004a479 --- /dev/null +++ b/src/test/run-make/sanitizer-thread/racy.rs @@ -0,0 +1,21 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::thread; + +static mut ANSWER: i32 = 0; + +fn main() { + let t1 = thread::spawn(|| unsafe { ANSWER = 42 }); + unsafe { + ANSWER = 24; + } + t1.join().ok(); +} diff --git a/src/test/rustdoc/impl-disambiguation.rs b/src/test/rustdoc/impl-disambiguation.rs new file mode 100644 index 0000000000000..afe1daf5983a2 --- /dev/null +++ b/src/test/rustdoc/impl-disambiguation.rs @@ -0,0 +1,40 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +pub trait Foo {} + +pub struct Bar { field: T } + +// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \ +// "impl Foo for Bar" +impl Foo for Bar {} +// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \ +// "impl Foo for Bar" +impl Foo for Bar {} +// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \ +// "impl<'a> Foo for &'a Bar" +impl<'a> Foo for &'a Bar {} + +pub mod mod1 { + pub struct Baz {} +} + +pub mod mod2 { + pub enum Baz {} +} + +// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \ +// "impl Foo for foo::mod1::Baz" +impl Foo for mod1::Baz {} +// @has foo/trait.Foo.html '//*[@class="item-list"]//code' \ +// "impl<'a> Foo for &'a foo::mod2::Baz" +impl<'a> Foo for &'a mod2::Baz {} diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 548a11439f5cc..0aefe703c9ca7 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -326,6 +326,8 @@ impl Builder { fn filename(&self, component: &str, target: &str) -> String { if component == "rust-src" { format!("rust-src-{}.tar.gz", self.channel) + } else if component == "cargo" { + format!("cargo-nightly-{}.tar.gz", target) } else { format!("{}-{}-{}.tar.gz", component, self.channel, target) }