about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs15
-rw-r--r--src/test/ui/sanitize/memory-passing.rs32
2 files changed, 44 insertions, 3 deletions
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 825011941a2..cf590a43826 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -340,17 +340,26 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
 
             sym::black_box => {
                 args[0].val.store(self, result);
-
+                let result_val_span = [result.llval];
                 // We need to "use" the argument in some way LLVM can't introspect, and on
                 // targets that support it we can typically leverage inline assembly to do
                 // this. LLVM's interpretation of inline assembly is that it's, well, a black
                 // box. This isn't the greatest implementation since it probably deoptimizes
                 // more than we want, but it's so far good enough.
+                //
+                // For zero-sized types, the location pointed to by the result may be
+                // uninitialized. Do not "use" the result in this case; instead just clobber
+                // the memory.
+                let (constraint, inputs): (&str, &[_]) = if result.layout.is_zst() {
+                    ("~{memory}", &[])
+                } else {
+                    ("r,~{memory}", &result_val_span)
+                };
                 crate::asm::inline_asm_call(
                     self,
                     "",
-                    "r,~{memory}",
-                    &[result.llval],
+                    constraint,
+                    inputs,
                     self.type_void(),
                     true,
                     false,
diff --git a/src/test/ui/sanitize/memory-passing.rs b/src/test/ui/sanitize/memory-passing.rs
new file mode 100644
index 00000000000..6d9b70ad6b1
--- /dev/null
+++ b/src/test/ui/sanitize/memory-passing.rs
@@ -0,0 +1,32 @@
+// needs-sanitizer-support
+// needs-sanitizer-memory
+//
+// revisions: unoptimized optimized
+//
+// [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O
+// [unoptimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins
+//
+// run-pass
+//
+// This test case intentionally limits the usage of the std,
+// since it will be linked with an uninstrumented version of it.
+
+#![feature(core_intrinsics)]
+#![feature(start)]
+#![allow(invalid_value)]
+
+use std::hint::black_box;
+
+fn calling_black_box_on_zst_ok() {
+    // It's OK to call black_box on a value of a zero-sized type, even if its
+    // underlying the memory location is uninitialized. For non-zero-sized types,
+    // this would be an MSAN error.
+    let zst = ();
+    black_box(zst);
+}
+
+#[start]
+fn main(_: isize, _: *const *const u8) -> isize {
+    calling_black_box_on_zst_ok();
+    0
+}