diff options
| author | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2022-11-12 17:25:00 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-11-12 17:25:00 +0100 |
| commit | 798815aec562f04bf9cd0ddbb8e8e03c906fb1cc (patch) | |
| tree | fc8a80e0b58977246cb21d404bd2d905ccbf0f4d | |
| parent | aa05f99001924004757ebd44b54bb6a4dd30c8bd (diff) | |
| parent | 0e0bcd95cda4293915ecd68921320a0928cdd0bb (diff) | |
| download | rust-798815aec562f04bf9cd0ddbb8e8e03c906fb1cc.tar.gz rust-798815aec562f04bf9cd0ddbb8e8e03c906fb1cc.zip | |
Rollup merge of #104110 - krasimirgg:msan-16, r=nagisa
prevent uninitialized access in black_box for zero-sized-types Don't read the pointer location in black_box for zero sized types, just emit a memory clobber instead. Addresses https://github.com/rust-lang/rust/issues/103304 when rust is build against LLVM at HEAD. Zulip thread: https://rust-lang.zulipchat.com/#narrow/stream/187780-t-compiler.2Fwg-llvm/topic/.28with.20llvm.20at.20HEAD.29.3A.20msan.20error.20in.20core.3A.3Ahint.3A.3Ablack_box
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/intrinsic.rs | 15 | ||||
| -rw-r--r-- | src/test/ui/sanitize/memory-passing.rs | 32 |
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 +} |
