Skip to content

Commit e40cc30

Browse files
authored
Rollup merge of rust-lang#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 rust-lang#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
2 parents c6d717f + 0e0bcd9 commit e40cc30

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

compiler/rustc_codegen_llvm/src/intrinsic.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -340,17 +340,26 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
340340

341341
sym::black_box => {
342342
args[0].val.store(self, result);
343-
343+
let result_val_span = [result.llval];
344344
// We need to "use" the argument in some way LLVM can't introspect, and on
345345
// targets that support it we can typically leverage inline assembly to do
346346
// this. LLVM's interpretation of inline assembly is that it's, well, a black
347347
// box. This isn't the greatest implementation since it probably deoptimizes
348348
// more than we want, but it's so far good enough.
349+
//
350+
// For zero-sized types, the location pointed to by the result may be
351+
// uninitialized. Do not "use" the result in this case; instead just clobber
352+
// the memory.
353+
let (constraint, inputs): (&str, &[_]) = if result.layout.is_zst() {
354+
("~{memory}", &[])
355+
} else {
356+
("r,~{memory}", &result_val_span)
357+
};
349358
crate::asm::inline_asm_call(
350359
self,
351360
"",
352-
"r,~{memory}",
353-
&[result.llval],
361+
constraint,
362+
inputs,
354363
self.type_void(),
355364
true,
356365
false,
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// needs-sanitizer-support
2+
// needs-sanitizer-memory
3+
//
4+
// revisions: unoptimized optimized
5+
//
6+
// [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O
7+
// [unoptimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins
8+
//
9+
// run-pass
10+
//
11+
// This test case intentionally limits the usage of the std,
12+
// since it will be linked with an uninstrumented version of it.
13+
14+
#![feature(core_intrinsics)]
15+
#![feature(start)]
16+
#![allow(invalid_value)]
17+
18+
use std::hint::black_box;
19+
20+
fn calling_black_box_on_zst_ok() {
21+
// It's OK to call black_box on a value of a zero-sized type, even if its
22+
// underlying the memory location is uninitialized. For non-zero-sized types,
23+
// this would be an MSAN error.
24+
let zst = ();
25+
black_box(zst);
26+
}
27+
28+
#[start]
29+
fn main(_: isize, _: *const *const u8) -> isize {
30+
calling_black_box_on_zst_ok();
31+
0
32+
}

0 commit comments

Comments
 (0)