]> git.lizzy.rs Git - rust.git/commitdiff
Link sanitizer runtimes instead of injecting crate dependencies
authorTomasz Miąsko <tomasz.miasko@gmail.com>
Thu, 7 Nov 2019 00:00:00 +0000 (00:00 +0000)
committerTomasz Miąsko <tomasz.miasko@gmail.com>
Thu, 9 Jan 2020 06:54:02 +0000 (07:54 +0100)
src/librustc_codegen_ssa/back/link.rs
src/librustc_metadata/creader.rs
src/librustc_session/session.rs
src/test/run-make-fulldeps/sanitizer-address/Makefile
src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile [deleted file]
src/test/run-make-fulldeps/sanitizer-invalid-cratetype/hello.rs [deleted file]
src/test/run-make-fulldeps/sanitizer-invalid-target/Makefile
src/test/run-make-fulldeps/sanitizer-leak/Makefile
src/test/run-make-fulldeps/sanitizer-memory/Makefile

index a53402ebb5c7daf54fab8f0277dcaa76f2cd613d..c91491fa54864ca3aeb14ab003615dcc70f17981 100644 (file)
@@ -531,6 +531,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
 
     {
         let mut linker = codegen_results.linker_info.to_linker(cmd, &sess, flavor, target_cpu);
+        link_sanitizer_runtime(sess, crate_type, &mut *linker);
         link_args::<B>(
             &mut *linker,
             flavor,
@@ -735,6 +736,47 @@ fn escape_string(s: &[u8]) -> String {
     }
 }
 
+fn link_sanitizer_runtime(sess: &Session, crate_type: config::CrateType, linker: &mut dyn Linker) {
+    let sanitizer = match &sess.opts.debugging_opts.sanitizer {
+        Some(s) => s,
+        None => return,
+    };
+
+    if crate_type != config::CrateType::Executable {
+        return;
+    }
+
+    let name = match sanitizer {
+        Sanitizer::Address => "asan",
+        Sanitizer::Leak => "lsan",
+        Sanitizer::Memory => "msan",
+        Sanitizer::Thread => "tsan",
+    };
+
+    let default_sysroot = filesearch::get_or_default_sysroot();
+    let default_tlib =
+        filesearch::make_target_lib_path(&default_sysroot, sess.opts.target_triple.triple());
+
+    match sess.opts.target_triple.triple() {
+        "x86_64-apple-darwin" => {
+            // On Apple platforms, the sanitizer is always built as a dylib, and
+            // LLVM will link to `@rpath/*.dylib`, so we need to specify an
+            // rpath to the library as well (the rpath should be absolute, see
+            // PR #41352 for details).
+            let libname = format!("rustc_rt.{}", name);
+            let rpath = default_tlib.to_str().expect("non-utf8 component in path");
+            linker.args(&["-Wl,-rpath".into(), "-Xlinker".into(), rpath.into()]);
+            linker.link_dylib(Symbol::intern(&libname));
+        }
+        "x86_64-unknown-linux-gnu" => {
+            let filename = format!("librustc_rt.{}.a", name);
+            let path = default_tlib.join(&filename);
+            linker.link_whole_rlib(&path);
+        }
+        _ => {}
+    }
+}
+
 /// Returns a boolean indicating whether the specified crate should be ignored
 /// during LTO.
 ///
@@ -1415,12 +1457,6 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
             _ if codegen_results.crate_info.profiler_runtime == Some(cnum) => {
                 add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, crate_type, cnum);
             }
-            _ if codegen_results.crate_info.sanitizer_runtime == Some(cnum)
-                && crate_type == config::CrateType::Executable =>
-            {
-                // Link the sanitizer runtimes only if we are actually producing an executable
-                link_sanitizer_runtime::<B>(cmd, sess, codegen_results, tmpdir, cnum);
-            }
             // compiler-builtins are always placed last to ensure that they're
             // linked correctly.
             _ if codegen_results.crate_info.compiler_builtins == Some(cnum) => {
@@ -1457,47 +1493,6 @@ 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<'a, B: ArchiveBuilder<'a>>(
-        cmd: &mut dyn Linker,
-        sess: &'a Session,
-        codegen_results: &CodegenResults,
-        tmpdir: &Path,
-        cnum: CrateNum,
-    ) {
-        let src = &codegen_results.crate_info.used_crate_source[&cnum];
-        let cratepath = &src.rlib.as_ref().unwrap().0;
-
-        if sess.target.target.options.is_like_osx {
-            // On Apple platforms, the sanitizer is always built as a dylib, and
-            // LLVM will link to `@rpath/*.dylib`, so we need to specify an
-            // rpath to the library as well (the rpath should be absolute, see
-            // PR #41352 for details).
-            //
-            // FIXME: Remove this logic into librustc_*san once Cargo supports it
-            let rpath = cratepath.parent().unwrap();
-            let rpath = rpath.to_str().expect("non-utf8 component in path");
-            cmd.args(&["-Wl,-rpath".into(), "-Xlinker".into(), rpath.into()]);
-        }
-
-        let dst = tmpdir.join(cratepath.file_name().unwrap());
-        let mut archive = <B as ArchiveBuilder>::new(sess, &dst, Some(cratepath));
-        archive.update_symbols();
-
-        for f in archive.src_files() {
-            if f.ends_with(RLIB_BYTECODE_EXTENSION) || f == METADATA_FILENAME {
-                archive.remove_file(&f);
-            }
-        }
-
-        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:
index b21715fadfe6f899b1caa4c8c03b6c13bc10c376..7ccc367be256054531d28bf4a4070a95f9557ca4 100644 (file)
@@ -6,7 +6,7 @@
 use rustc::hir::map::Definitions;
 use rustc::middle::cstore::DepKind;
 use rustc::middle::cstore::{CrateSource, ExternCrate, ExternCrateSource, MetadataLoaderDyn};
-use rustc::session::config::{self, Sanitizer};
+use rustc::session::config;
 use rustc::session::search_paths::PathKind;
 use rustc::session::{CrateDisambiguator, Session};
 use rustc::ty::TyCtxt;
@@ -674,108 +674,6 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
         self.inject_dependency_if(cnum, "a panic runtime", &|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 on some tested platforms with
-            // executables linked to `std`
-            const ASAN_SUPPORTED_TARGETS: &[&str] =
-                &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
-            const TSAN_SUPPORTED_TARGETS: &[&str] =
-                &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
-            const LSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"];
-            const MSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"];
-
-            let supported_targets = match *sanitizer {
-                Sanitizer::Address => ASAN_SUPPORTED_TARGETS,
-                Sanitizer::Thread => TSAN_SUPPORTED_TARGETS,
-                Sanitizer::Leak => LSAN_SUPPORTED_TARGETS,
-                Sanitizer::Memory => MSAN_SUPPORTED_TARGETS,
-            };
-            if !supported_targets.contains(&&*self.sess.opts.target_triple.triple()) {
-                self.sess.err(&format!(
-                    "{:?}Sanitizer only works with the `{}` target",
-                    sanitizer,
-                    supported_targets.join("` or `")
-                ));
-                return;
-            }
-
-            // firstyear 2017 - during testing I was unable to access an OSX machine
-            // to make this work on different crate types. As a result, today I have
-            // only been able to test and support linux as a target.
-            if self.sess.opts.target_triple.triple() == "x86_64-unknown-linux-gnu" {
-                if !self.sess.crate_types.borrow().iter().all(|ct| {
-                    match *ct {
-                        // Link the runtime
-                        config::CrateType::Executable => true,
-                        // This crate will be compiled with the required
-                        // instrumentation pass
-                        config::CrateType::Staticlib
-                        | config::CrateType::Rlib
-                        | config::CrateType::Dylib
-                        | config::CrateType::Cdylib => false,
-                        _ => {
-                            self.sess.err(&format!(
-                                "Only executables, staticlibs, \
-                                cdylibs, dylibs and rlibs can be compiled with \
-                                `-Z sanitizer`"
-                            ));
-                            false
-                        }
-                    }
-                }) {
-                    return;
-                }
-            } else {
-                if !self.sess.crate_types.borrow().iter().all(|ct| {
-                    match *ct {
-                        // Link the runtime
-                        config::CrateType::Executable => true,
-                        // This crate will be compiled with the required
-                        // instrumentation pass
-                        config::CrateType::Rlib => 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() == sym::std {
-                    uses_std = true;
-                }
-            });
-
-            if uses_std {
-                let name = Symbol::intern(match sanitizer {
-                    Sanitizer::Address => "rustc_asan",
-                    Sanitizer::Leak => "rustc_lsan",
-                    Sanitizer::Memory => "rustc_msan",
-                    Sanitizer::Thread => "rustc_tsan",
-                });
-                info!("loading sanitizer: {}", name);
-
-                let cnum = self.resolve_crate(name, DUMMY_SP, DepKind::Explicit, None);
-                let data = self.cstore.get_crate_data(cnum);
-
-                // 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));
-                }
-            } else {
-                self.sess.err("Must link std to be compiled with `-Z sanitizer`");
-            }
-        }
-    }
-
     fn inject_profiler_runtime(&mut self) {
         if self.sess.opts.debugging_opts.profile || self.sess.opts.cg.profile_generate.enabled() {
             info!("loading profiler");
@@ -927,7 +825,6 @@ fn inject_dependency_if(
     }
 
     pub fn postprocess(&mut self, krate: &ast::Crate) {
-        self.inject_sanitizer_runtime();
         self.inject_profiler_runtime();
         self.inject_allocator_crate(krate);
         self.inject_panic_runtime(krate);
index dba5b9f3f14c229f47a326de065107e9e7ed0a6a..d979247b46d3af81bb97d307a6575d966f0c3d97 100644 (file)
@@ -1124,6 +1124,32 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
                   See https://github.com/rust-lang/rust/issues/61002 for details.",
         );
     }
+
+    // Sanitizers can only be used on some tested platforms.
+    if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer {
+        const ASAN_SUPPORTED_TARGETS: &[&str] =
+            &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
+        const TSAN_SUPPORTED_TARGETS: &[&str] =
+            &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
+        const LSAN_SUPPORTED_TARGETS: &[&str] =
+            &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
+        const MSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"];
+
+        let supported_targets = match *sanitizer {
+            Sanitizer::Address => ASAN_SUPPORTED_TARGETS,
+            Sanitizer::Thread => TSAN_SUPPORTED_TARGETS,
+            Sanitizer::Leak => LSAN_SUPPORTED_TARGETS,
+            Sanitizer::Memory => MSAN_SUPPORTED_TARGETS,
+        };
+
+        if !supported_targets.contains(&&*sess.opts.target_triple.triple()) {
+            sess.err(&format!(
+                "{:?}Sanitizer only works with the `{}` target",
+                sanitizer,
+                supported_targets.join("` or `")
+            ));
+        }
+    }
 }
 
 /// Hash value constructed out of all the `-C metadata` arguments passed to the
index 3a377c32993d5497ef982964a1198944b3c9df4d..7f5e9049b2f77e3acd72cb1bef34b33ef39e377e 100644 (file)
@@ -23,7 +23,7 @@ endif
 endif
 
 all:
-       $(RUSTC) -g -Z sanitizer=address -Z print-link-args $(EXTRA_RUSTFLAG) overflow.rs | $(CGREP) librustc_asan
+       $(RUSTC) -g -Z sanitizer=address -Z print-link-args $(EXTRA_RUSTFLAG) overflow.rs | $(CGREP) rustc_rt.asan
        # Verify that stack buffer overflow is detected:
        $(TMPDIR)/overflow 2>&1 | $(CGREP) stack-buffer-overflow
        # Verify that variable name is included in address sanitizer report:
diff --git a/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile b/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/Makefile
deleted file mode 100644 (file)
index 9581ac5..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# needs-sanitizer-support
-
--include ../tools.mk
-
-# NOTE the address sanitizer only supports x86_64 linux and macOS
-
-ifeq ($(TARGET),x86_64-apple-darwin)
-EXTRA_RUSTFLAG=-C rpath
-else
-ifeq ($(TARGET),x86_64-unknown-linux-gnu)
-EXTRA_RUSTFLAG=
-endif
-endif
-
-all:
-       $(RUSTC) -Z sanitizer=address --crate-type proc-macro --target $(TARGET) hello.rs 2>&1 | $(CGREP) '-Z sanitizer'
diff --git a/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/hello.rs b/src/test/run-make-fulldeps/sanitizer-invalid-cratetype/hello.rs
deleted file mode 100644 (file)
index e7a11a9..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
-    println!("Hello, world!");
-}
index df8afee15ce073856f3ddf33695eed614a5b379f..2a23f0fe3d4ef1d5465db9e0b7ecf59ac0c44b9c 100644 (file)
@@ -2,4 +2,4 @@
 
 all:
        $(RUSTC) -Z sanitizer=leak --target i686-unknown-linux-gnu hello.rs 2>&1 | \
-               $(CGREP) 'LeakSanitizer only works with the `x86_64-unknown-linux-gnu` target'
+               $(CGREP) 'LeakSanitizer only works with the `x86_64-unknown-linux-gnu` or `x86_64-apple-darwin` target'
index 101e8272ab91e40114655aef9eeed17c77b28fe4..d8598b8ac93f90815226bf832d06c647d8bc6dac 100644 (file)
@@ -7,5 +7,5 @@
 # FIXME(#46126) ThinLTO for libstd broke this test
 
 all:
-       $(RUSTC) -C opt-level=1 -g -Z sanitizer=leak -Z print-link-args leak.rs | $(CGREP) librustc_lsan
+       $(RUSTC) -C opt-level=1 -g -Z sanitizer=leak -Z print-link-args leak.rs | $(CGREP) rustc_rt.lsan
        $(TMPDIR)/leak 2>&1 | $(CGREP) 'detected memory leaks'
index f5787903a2b594e3e6f440e3c6f25f086423da7d..8bc9df1b4baebbaa5d23d2521e1891439df19d97 100644 (file)
@@ -5,7 +5,7 @@
 # only-x86_64
 
 all:
-       $(RUSTC) -g -Z sanitizer=memory -Z print-link-args uninit.rs | $(CGREP) librustc_msan
+       $(RUSTC) -g -Z sanitizer=memory -Z print-link-args uninit.rs | $(CGREP) rustc_rt.msan
        $(TMPDIR)/uninit 2>&1 | $(CGREP) use-of-uninitialized-value
-       $(RUSTC) -g -Z sanitizer=memory -Z print-link-args maybeuninit.rs | $(CGREP) librustc_msan
+       $(RUSTC) -g -Z sanitizer=memory -Z print-link-args maybeuninit.rs | $(CGREP) rustc_rt.msan
        $(TMPDIR)/maybeuninit 2>&1 | $(CGREP) use-of-uninitialized-value