about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTomasz Miąsko <tomasz.miasko@gmail.com>2019-11-15 00:00:00 +0000
committerTomasz Miąsko <tomasz.miasko@gmail.com>2019-11-22 19:32:45 +0100
commit9b907032891712c21ef9c8ff20c46cd2b20fcf30 (patch)
tree356729cea279c0c86f2b3389ed9ca473057d3a0a
parent317f68ab10c04719d54265f92784618afed914b6 (diff)
downloadrust-9b907032891712c21ef9c8ff20c46cd2b20fcf30.tar.gz
rust-9b907032891712c21ef9c8ff20c46cd2b20fcf30.zip
Add support for sanitizer recovery
-rw-r--r--src/librustc/session/config.rs51
-rw-r--r--src/librustc_codegen_llvm/back/write.rs3
-rw-r--r--src/librustc_codegen_ssa/back/write.rs3
-rw-r--r--src/test/codegen/sanitizer-recover.rs34
4 files changed, 80 insertions, 11 deletions
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 50752bac30f..afcbafd8a00 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -43,7 +43,7 @@ pub struct Config {
     pub usize_ty: UintTy,
 }
 
-#[derive(Clone, Hash, Debug)]
+#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub enum Sanitizer {
     Address,
     Leak,
@@ -51,6 +51,19 @@ pub enum Sanitizer {
     Thread,
 }
 
+impl FromStr for Sanitizer {
+    type Err = ();
+    fn from_str(s: &str) -> Result<Sanitizer, ()> {
+        match s {
+            "address" => Ok(Sanitizer::Address),
+            "leak" => Ok(Sanitizer::Leak),
+            "memory" => Ok(Sanitizer::Memory),
+            "thread" => Ok(Sanitizer::Thread),
+            _ => Err(()),
+        }
+    }
+}
+
 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
 pub enum OptLevel {
     No,         // -O0
@@ -819,6 +832,8 @@ macro_rules! options {
             Some("one of: `full`, `partial`, or `off`");
         pub const parse_sanitizer: Option<&str> =
             Some("one of: `address`, `leak`, `memory` or `thread`");
+        pub const parse_sanitizer_list: Option<&str> =
+            Some("comma separated list of sanitizers");
         pub const parse_linker_flavor: Option<&str> =
             Some(::rustc_target::spec::LinkerFlavor::one_of());
         pub const parse_optimization_fuel: Option<&str> =
@@ -1013,15 +1028,30 @@ macro_rules! options {
             true
         }
 
-        fn parse_sanitizer(slote: &mut Option<Sanitizer>, 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,
+        fn parse_sanitizer(slot: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
+            if let Some(Ok(s)) =  v.map(str::parse) {
+                *slot = Some(s);
+                true
+            } else {
+                false
+            }
+        }
+
+        fn parse_sanitizer_list(slot: &mut Vec<Sanitizer>, v: Option<&str>) -> bool {
+            if let Some(v) = v {
+                for s in v.split(',').map(str::parse) {
+                    if let Ok(s) = s {
+                        if !slot.contains(&s) {
+                            slot.push(s);
+                        }
+                    } else {
+                        return false;
+                    }
+                }
+                true
+            } else {
+                false
             }
-            true
         }
 
         fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
@@ -1379,6 +1409,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "pass `-install_name @rpath/...` to the macOS linker"),
     sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
                                     "use a sanitizer"),
+    sanitizer_recover: Vec<Sanitizer> = (vec![], parse_sanitizer_list, [TRACKED],
+        "Enable recovery for selected sanitizers"),
     fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
         "set the optimization fuel quota for a crate"),
     print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
@@ -2984,6 +3016,7 @@ mod dep_tracking {
         Option<cstore::NativeLibraryKind>
     ));
     impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
+    impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
 
     impl<T1, T2> DepTrackingHash for (T1, T2)
     where
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index 89728245eea..1b94cc605a5 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -364,9 +364,9 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,
             }
 
             if let Some(sanitizer) = &config.sanitizer {
+                let recover = config.sanitizer_recover.contains(sanitizer);
                 match sanitizer {
                     Sanitizer::Address => {
-                        let recover = false;
                         extra_passes.push(llvm::LLVMRustCreateAddressSanitizerFunctionPass(
                                 recover));
                         extra_passes.push(llvm::LLVMRustCreateModuleAddressSanitizerPass(
@@ -374,7 +374,6 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>,
                     }
                     Sanitizer::Memory => {
                         let track_origins = 0;
-                        let recover = false;
                         extra_passes.push(llvm::LLVMRustCreateMemorySanitizerPass(
                                 track_origins, recover));
                     }
diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs
index e11a1ab6ee8..f80869132c0 100644
--- a/src/librustc_codegen_ssa/back/write.rs
+++ b/src/librustc_codegen_ssa/back/write.rs
@@ -60,6 +60,7 @@ pub struct ModuleConfig {
     pub pgo_use: Option<PathBuf>,
 
     pub sanitizer: Option<Sanitizer>,
+    pub sanitizer_recover: Vec<Sanitizer>,
 
     // Flags indicating which outputs to produce.
     pub emit_pre_lto_bc: bool,
@@ -100,6 +101,7 @@ impl ModuleConfig {
             pgo_use: None,
 
             sanitizer: None,
+            sanitizer_recover: Default::default(),
 
             emit_no_opt_bc: false,
             emit_pre_lto_bc: false,
@@ -356,6 +358,7 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
     modules_config.pgo_gen = sess.opts.cg.profile_generate.clone();
     modules_config.pgo_use = sess.opts.cg.profile_use.clone();
     modules_config.sanitizer = sess.opts.debugging_opts.sanitizer.clone();
+    modules_config.sanitizer_recover = sess.opts.debugging_opts.sanitizer_recover.clone();
     modules_config.opt_level = Some(sess.opts.optimize);
     modules_config.opt_size = Some(sess.opts.optimize);
 
diff --git a/src/test/codegen/sanitizer-recover.rs b/src/test/codegen/sanitizer-recover.rs
new file mode 100644
index 00000000000..a292332667b
--- /dev/null
+++ b/src/test/codegen/sanitizer-recover.rs
@@ -0,0 +1,34 @@
+// Verifies that AddressSanitizer and MemorySanitizer
+// recovery mode can be enabled with -Zsanitizer-recover.
+//
+// needs-sanitizer-support
+// only-linux
+// only-x86_64
+// revisions:ASAN ASAN-RECOVER MSAN MSAN-RECOVER
+//
+//[ASAN]         compile-flags: -Zsanitizer=address
+//[ASAN-RECOVER] compile-flags: -Zsanitizer=address -Zsanitizer-recover=address
+//[MSAN]         compile-flags: -Zsanitizer=memory
+//[MSAN-RECOVER] compile-flags: -Zsanitizer=memory  -Zsanitizer-recover=memory
+
+#![crate_type="lib"]
+
+// ASAN-LABEL:         define i32 @penguin(
+// ASAN-RECOVER-LABEL: define i32 @penguin(
+// MSAN-LABEL:         define i32 @penguin(
+// MSAN-RECOVER-LABEL: define i32 @penguin(
+#[no_mangle]
+pub fn penguin(p: &mut i32) -> i32 {
+    // ASAN:             call void @__asan_report_load4(i64 %0)
+    // ASAN:             unreachable
+    //
+    // ASAN-RECOVER:     call void @__asan_report_load4_noabort(
+    // ASAN-RECOVER-NOT: unreachable
+    //
+    // MSAN:             call void @__msan_warning_noreturn()
+    // MSAN:             unreachable
+    //
+    // MSAN-RECOVER:     call void @__msan_warning()
+    // MSAN-RECOVER-NOT: unreachable
+    *p
+}