Skip to content

Commit 2b3dda6

Browse files
[sanitizer][msan] fix AArch64 vararg support for KMSAN
Cast StackSaveAreaPtr, GrRegSaveAreaPtr, VrRegSaveAreaPtr to pointers to fix assertions in getShadowOriginPtrKernel(). Also add an isPointerTy() assertion to getShadowOriginPtrUserspace() to ensure both the userspace and the kernel implementations of getShadowOriginPtr() have the same expectations. Fixes: #69738 Patch by Mark Johnston.
1 parent 4326497 commit 2b3dda6

File tree

3 files changed

+65
-3
lines changed

3 files changed

+65
-3
lines changed

llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,6 +1717,12 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
17171717
std::pair<Value *, Value *>
17181718
getShadowOriginPtrUserspace(Value *Addr, IRBuilder<> &IRB, Type *ShadowTy,
17191719
MaybeAlign Alignment) {
1720+
VectorType *VectTy = dyn_cast<VectorType>(Addr->getType());
1721+
if (!VectTy) {
1722+
assert(Addr->getType()->isPointerTy());
1723+
} else {
1724+
assert(VectTy->getElementType()->isPointerTy());
1725+
}
17201726
Type *IntptrTy = ptrToIntPtrType(Addr->getType());
17211727
Value *ShadowOffset = getShadowPtrOffset(Addr, IRB);
17221728
Value *ShadowLong = ShadowOffset;
@@ -5258,21 +5264,25 @@ struct VarArgAArch64Helper : public VarArgHelper {
52585264
// we need to adjust the offset for both GR and VR fields based on
52595265
// the __{gr,vr}_offs value (since they are stores based on incoming
52605266
// named arguments).
5267+
Type *RegSaveAreaPtrTy = IRB.getInt8PtrTy();
52615268

52625269
// Read the stack pointer from the va_list.
5263-
Value *StackSaveAreaPtr = getVAField64(IRB, VAListTag, 0);
5270+
Value *StackSaveAreaPtr =
5271+
IRB.CreateIntToPtr(getVAField64(IRB, VAListTag, 0), RegSaveAreaPtrTy);
52645272

52655273
// Read both the __gr_top and __gr_off and add them up.
52665274
Value *GrTopSaveAreaPtr = getVAField64(IRB, VAListTag, 8);
52675275
Value *GrOffSaveArea = getVAField32(IRB, VAListTag, 24);
52685276

5269-
Value *GrRegSaveAreaPtr = IRB.CreateAdd(GrTopSaveAreaPtr, GrOffSaveArea);
5277+
Value *GrRegSaveAreaPtr = IRB.CreateIntToPtr(
5278+
IRB.CreateAdd(GrTopSaveAreaPtr, GrOffSaveArea), RegSaveAreaPtrTy);
52705279

52715280
// Read both the __vr_top and __vr_off and add them up.
52725281
Value *VrTopSaveAreaPtr = getVAField64(IRB, VAListTag, 16);
52735282
Value *VrOffSaveArea = getVAField32(IRB, VAListTag, 28);
52745283

5275-
Value *VrRegSaveAreaPtr = IRB.CreateAdd(VrTopSaveAreaPtr, VrOffSaveArea);
5284+
Value *VrRegSaveAreaPtr = IRB.CreateIntToPtr(
5285+
IRB.CreateAdd(VrTopSaveAreaPtr, VrOffSaveArea), RegSaveAreaPtrTy);
52765286

52775287
// It does not know how many named arguments is being used and, on the
52785288
// callsite all the arguments were saved. Since __gr_off is defined as
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
; RUN: opt < %s -S -passes=msan -msan-kernel=1 2>&1 | FileCheck %s
2+
3+
target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
4+
target triple = "aarch64-unknown-linux-gnu"
5+
6+
%struct.__va_list = type { ptr, ptr, ptr, i32, i32 }
7+
8+
define i32 @foo(i32 %guard, ...) {
9+
%vl = alloca %struct.__va_list, align 8
10+
call void @llvm.lifetime.start.p0(i64 32, ptr %vl)
11+
call void @llvm.va_start(ptr %vl)
12+
call void @llvm.va_end(ptr %vl)
13+
call void @llvm.lifetime.end.p0(i64 32, ptr %vl)
14+
ret i32 0
15+
}
16+
17+
; First check if the variadic shadow values are saved in stack with correct
18+
; size (192 is total of general purpose registers size, 64, plus total of
19+
; floating-point registers size, 128).
20+
21+
; CHECK-LABEL: @foo
22+
; CHECK: [[A:%.*]] = load {{.*}} ptr %va_arg_overflow_size
23+
; CHECK: [[B:%.*]] = add i64 192, [[A]]
24+
; CHECK: alloca {{.*}} [[B]]
25+
26+
; We expect three memcpy operations: one for the general purpose registers,
27+
; one for floating-point/SIMD ones, and one for thre remaining arguments.
28+
29+
; Propagate the GR shadow values on for the va_list::__gp_top, adjust the
30+
; offset in the __msan_va_arg_tls based on va_list:__gp_off, and finally
31+
; issue the memcpy.
32+
; CHECK: [[GRP:%.*]] = getelementptr inbounds i8, ptr {{%.*}}, i64 {{%.*}}
33+
; CHECK: [[GRSIZE:%.*]] = sub i64 64, {{%.*}}
34+
; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 {{%.*}}, ptr align 8 [[GRP]], i64 [[GRSIZE]], i1 false)
35+
36+
; Propagate the VR shadow values on for the va_list::__vr_top, adjust the
37+
; offset in the __msan_va_arg_tls based on va_list:__vr_off, and finally
38+
; issue the memcpy.
39+
; CHECK: [[VRP:%.*]] = getelementptr inbounds i8, ptr {{%.*}}, i64 {{%.*}}
40+
; CHECK: [[VRSIZE:%.*]] = sub i64 128, {{%.*}}
41+
; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 {{%.*}}, ptr align 8 [[VRP]], i64 [[VRSIZE]], i1 false)
42+
43+
; Copy the remaining shadow values on the va_list::__stack position (it is
44+
; on the constant offset of 192 from __msan_va_arg_tls).
45+
; CHECK: [[STACK:%.*]] = getelementptr inbounds i8, ptr {{%.*}}, i32 192
46+
; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 16 {{%.*}}, ptr align 16 [[STACK]], i64 {{%.*}}, i1 false)
47+
48+
declare void @llvm.lifetime.start.p0(i64, ptr nocapture) #1
49+
declare void @llvm.va_start(ptr) #2
50+
declare void @llvm.va_end(ptr) #2
51+
declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #1

llvm/test/Instrumentation/MemorySanitizer/X86/vararg.ll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
; RUN: opt < %s -msan-check-access-address=0 -S -passes=msan 2>&1
2+
; RUN: opt < %s -msan-check-access-address=0 -S -passes=msan -msan-kernel=1 2>&1
23
; Test that code using va_start can be compiled on i386.
34

45
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128"

0 commit comments

Comments
 (0)