diff --git a/configure b/configure index 597f00763364..c751ad9731a7 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 34aee77ae210..000000000000 --- 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 34aee77ae210..000000000000 --- 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 53721d48d977..09aefd45e94c 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 0ebd10551329..cbfbcbe4f0c6 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 81dd42a1e906..0b1a1f39d8d4 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 4e67a14345b9..604c0397d524 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 @@ pub fn parse(build: &str, file: Option) -> 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 @@ macro_rules! check { ("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 a53419ad7fd7..025fe990f91d 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 1c3901bf2a14..2da2892150b4 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 e58dcc9fce92..ba6b34343f0b 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -599,7 +599,8 @@ fn prepare_tool_cmd(&self, compiler: &Compiler, cmd: &mut Command) { /// 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 4e4f5dd6f1e5..12e24ff1af6a 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 000000000000..4ce38fd9205e --- /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 6919487e17c3..e903b6ddc64c 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 a8fc4c169fac..d30da544a8af 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 f9013490418f..8aefabe61fdf 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 6537cc1adce0..2d80fc32c469 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -229,6 +229,7 @@ fn dylib_dependency_formats(&self, cnum: CrateNum) 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 @@ fn export_macros(&self, cnum: CrateNum) { bug!("export_macros") } 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 d41c2ba93b93..24615f2fa699 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 @@ mod $mod_desc { 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 @@ fn parse_panic_strategy(slot: &mut Option, v: Option<&str>) -> bo } 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 @@ fn parse_panic_strategy(slot: &mut Option, v: Option<&str>) -> bo "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 000000000000..2d4872b1fc94 --- /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 000000000000..015be14bd495 --- /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 000000000000..71a166b91ebc --- /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 07d36448ab0f..949e949f673a 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 000000000000..bc1f2ead7688 --- /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 000000000000..5773777d1f81 --- /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 000000000000..71a166b91ebc --- /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 81a4f7c93b6e..55dc5aa2876f 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -17,7 +17,8 @@ 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 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) { &|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 @@ fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod, 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 beba5faf3d03..4709ca6101c7 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -297,6 +297,11 @@ pub fn is_compiler_builtins(&self) -> bool { 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 39581a469608..7b0177bfd23e 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -297,6 +297,10 @@ fn is_compiler_builtins(&self, cnum: CrateNum) -> bool { 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 000000000000..45cc6b9839fb --- /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 000000000000..7a4c8f707393 --- /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 000000000000..71a166b91ebc --- /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 4ddf8a883bc4..1cbfa26b705a 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 unlib<'a>(config: &config::Config, stem: &'a str) -> &'a str { } } + // 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 9a761e17e75e..5c4a5a9a4423 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -12,7 +12,7 @@ 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 bf7a02eb0f19..7ac482459ee3 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 000000000000..66d6236361ea --- /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 000000000000..84326ae8a710 --- /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 000000000000..71a166b91ebc --- /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 60dae19d876c..c591c09bf20e 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 40eb7e5ab78c..6234d8902444 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2132,10 +2132,23 @@ fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::
    ")?; 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 trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean:: 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 8146e7fb1eda..2ba7517d3d20 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 e26415392949..1ef2cb4ed153 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 a78c192a120d..cc0a67b3d2e9 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -328,6 +328,10 @@ pub fn new() -> 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 fn is_builtin_attr(attr: &ast::Attribute) -> bool { 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 14c9c5544b18..db96079d3e91 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 4e201c254e39..f3b52b71b99c 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 a30fa3133e28..0baf5528e935 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 000000000000..a18641d82469 --- /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 000000000000..78d96398b958 --- /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 000000000000..5931145f3a47 --- /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 000000000000..e35c3873f7eb --- /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 000000000000..835d5b0d9d8c --- /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 000000000000..41782851a1a6 --- /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 000000000000..6a1ce8bab2fb --- /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 000000000000..e9e46b7702a8 --- /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 000000000000..f02d948fdc84 --- /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 000000000000..279da6aaae70 --- /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 000000000000..08682e5975e5 --- /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 000000000000..8350c7de3aca --- /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 000000000000..8bb89a241cb0 --- /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 000000000000..dc929e004a47 --- /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 000000000000..afe1daf5983a --- /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 548a11439f5c..0aefe703c9ca 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -326,6 +326,8 @@ fn url(&self, component: &str, target: &str) -> String { 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) }