Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9b91c54

Browse files
authored
[msan] Unpoison indirect outputs for userspace using memset for large operands (#79924)
Modify #77393 to clear shadow memory using `llvm.memset.*` when the size is large, similar to `shouldUseBZeroPlusStoresToInitialize` in clang for `-ftrivial-auto-var-init=`. The intrinsic, if lowered to libcall, will use the msan interceptor. The instruction selector lowers a `StoreInst` to multiple stores, not utilizing `memset`. When the size is large (e.g. `store { [100 x i32] } zeroinitializer, ptr %12, align 1`), the generated code will be long (and `CodeGenPrepare::optimizeInst` will even crash for a huge size). ``` // Test stack size template <class T> void DoNotOptimize(const T& var) { // deprecated by google/benchmark#1493 asm volatile("" : "+m"(const_cast<T&>(var))); } int main() { using LargeArray = std::array<int, 1000000>; auto large_stack = []() { DoNotOptimize(LargeArray()); }; /////// CodeGenPrepare::optimizeInst triggers an assertion failure when creating an integer type with a bit width>2**23 large_stack(); } ```
1 parent d942339 commit 9b91c54

File tree

2 files changed

+22
-4
lines changed

2 files changed

+22
-4
lines changed

llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -4552,16 +4552,22 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
45524552
}
45534553
if (!ElemTy->isSized())
45544554
return;
4555-
Value *SizeVal =
4556-
IRB.CreateTypeSize(MS.IntptrTy, DL.getTypeStoreSize(ElemTy));
4555+
auto Size = DL.getTypeStoreSize(ElemTy);
4556+
Value *SizeVal = IRB.CreateTypeSize(MS.IntptrTy, Size);
45574557
if (MS.CompileKernel) {
45584558
IRB.CreateCall(MS.MsanInstrumentAsmStoreFn, {Operand, SizeVal});
45594559
} else {
45604560
// ElemTy, derived from elementtype(), does not encode the alignment of
45614561
// the pointer. Conservatively assume that the shadow memory is unaligned.
4562+
// When Size is large, avoid StoreInst as it would expand to many
4563+
// instructions.
45624564
auto [ShadowPtr, _] =
45634565
getShadowOriginPtrUserspace(Operand, IRB, IRB.getInt8Ty(), Align(1));
4564-
IRB.CreateAlignedStore(getCleanShadow(ElemTy), ShadowPtr, Align(1));
4566+
if (Size <= 32)
4567+
IRB.CreateAlignedStore(getCleanShadow(ElemTy), ShadowPtr, Align(1));
4568+
else
4569+
IRB.CreateMemSet(ShadowPtr, ConstantInt::getNullValue(IRB.getInt8Ty()),
4570+
SizeVal, Align(1));
45654571
}
45664572
}
45674573

llvm/test/Instrumentation/MemorySanitizer/msan_asm_conservative.ll

+13-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
1414
target triple = "x86_64-unknown-linux-gnu"
1515

1616
%struct.pair = type { i32, i32 }
17+
%struct.large = type { [33 x i8] }
1718

1819
@id1 = common dso_local global i32 0, align 4
1920
@is1 = common dso_local global i32 0, align 4
@@ -28,6 +29,7 @@ target triple = "x86_64-unknown-linux-gnu"
2829
@memcpy_d2 = common dso_local global ptr null, align 8
2930
@memcpy_s1 = common dso_local global ptr null, align 8
3031
@memcpy_s2 = common dso_local global ptr null, align 8
32+
@large = common dso_local global %struct.pair zeroinitializer, align 4
3133

3234
; The functions below were generated from a C source that contains declarations like follows:
3335
; void f1() {
@@ -201,7 +203,6 @@ entry:
201203
; CHECK: call void @__msan_warning
202204
; CHECK: call i32 asm "", "=r,=*m,r,*m,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(i32) @id1, i32 [[IS1_F7]], ptr elementtype(i32) @is1)
203205

204-
205206
; Three outputs, first and last returned via regs, second via mem:
206207
; asm("" : "=r" (id1), "=m"(id2), "=r" (id3):);
207208
define dso_local void @f_3o_reg_mem_reg() sanitize_memory {
@@ -265,6 +266,17 @@ entry:
265266
; CHECK-CONS: call void @__msan_instrument_asm_store({{.*}}@memcpy_d1{{.*}}, i64 8)
266267
; CHECK: call void asm "", "=*m,=*m,=*m,*m,*m,*m,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(%struct.pair) @pair2, ptr elementtype(i8) @c2, ptr elementtype(ptr) @memcpy_d1, ptr elementtype(%struct.pair) @pair1, ptr elementtype(i8) @c1, ptr elementtype(ptr) @memcpy_s1)
267268

269+
; Use memset when the size is larger.
270+
define dso_local void @f_1i_1o_mem_large() sanitize_memory {
271+
entry:
272+
%0 = call i32 asm "", "=r,=*m,*m,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(%struct.large) @large, ptr elementtype(%struct.large) @large)
273+
store i32 %0, ptr @id1, align 4
274+
ret void
275+
}
276+
; CHECK-LABEL: @f_1i_1o_mem_large(
277+
; USER-CONS: call void @llvm.memset.p0.i64(ptr align 1 inttoptr (i64 xor (i64 ptrtoint (ptr @large to i64), i64 87960930222080) to ptr), i8 0, i64 33, i1 false)
278+
; CHECK-CONS: call void @__msan_instrument_asm_store({{.*}}@large{{.*}}, i64 33)
279+
; CHECK: call i32 asm "", "=r,=*m,*m,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(%struct.large) @large, ptr elementtype(%struct.large) @large)
268280

269281
; A simple asm goto construct to check that callbr is handled correctly:
270282
; int asm_goto(int n) {

0 commit comments

Comments
 (0)