Skip to content

Commit de71056

Browse files
committed
[ASAN] Initial support memory checks on scalable vector typed allocas
This patch adjusts the memory instrumentation to account for scalable vector types in allocas. Note that we don't allow scalable vector globals, so we don't need to update that codepath. A couple points. First, this simply disables the optimization for scalable allocas. We can revisit this in the future, but it requires a bit of plumbing to get scalable object sizes through the visitor to be useful. Second, I am simply disabling stack poisoning for scalable vector allocas. This is mostly for staging the change as I can't write a working test for memory instrumentation without doing so. I don't think it's unreasonable to do on it's own basis as without the bailout, we crash the compiler. Differential Revision: https://reviews.llvm.org/D145259
1 parent 8c258fd commit de71056

File tree

2 files changed

+74
-4
lines changed

2 files changed

+74
-4
lines changed

llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -667,15 +667,15 @@ struct AddressSanitizer {
667667
assert(this->UseAfterReturn != AsanDetectStackUseAfterReturnMode::Invalid);
668668
}
669669

670-
uint64_t getAllocaSizeInBytes(const AllocaInst &AI) const {
670+
TypeSize getAllocaSizeInBytes(const AllocaInst &AI) const {
671671
uint64_t ArraySize = 1;
672672
if (AI.isArrayAllocation()) {
673673
const ConstantInt *CI = dyn_cast<ConstantInt>(AI.getArraySize());
674674
assert(CI && "non-constant array size");
675675
ArraySize = CI->getZExtValue();
676676
}
677677
Type *Ty = AI.getAllocatedType();
678-
uint64_t SizeInBytes =
678+
TypeSize SizeInBytes =
679679
AI.getModule()->getDataLayout().getTypeAllocSize(Ty);
680680
return SizeInBytes * ArraySize;
681681
}
@@ -1040,7 +1040,9 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> {
10401040

10411041
/// Collect Alloca instructions we want (and can) handle.
10421042
void visitAllocaInst(AllocaInst &AI) {
1043-
if (!ASan.isInterestingAlloca(AI)) {
1043+
// FIXME: Handle scalable vectors instead of ignoring them.
1044+
if (!ASan.isInterestingAlloca(AI) ||
1045+
isa<ScalableVectorType>(AI.getAllocatedType())) {
10441046
if (AI.isStaticAlloca()) {
10451047
// Skip over allocas that are present *before* the first instrumented
10461048
// alloca, we don't want to move those around.
@@ -1254,7 +1256,7 @@ bool AddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
12541256
bool IsInteresting =
12551257
(AI.getAllocatedType()->isSized() &&
12561258
// alloca() may be called with 0 size, ignore it.
1257-
((!AI.isStaticAlloca()) || getAllocaSizeInBytes(AI) > 0) &&
1259+
((!AI.isStaticAlloca()) || !getAllocaSizeInBytes(AI).isZero()) &&
12581260
// We are only interested in allocas not promotable to registers.
12591261
// Promotable allocas are common under -O0.
12601262
(!ClSkipPromotableAllocas || !isAllocaPromotable(&AI)) &&
@@ -3492,6 +3494,10 @@ void FunctionStackPoisoner::handleDynamicAllocaCall(AllocaInst *AI) {
34923494
// constant inbounds index.
34933495
bool AddressSanitizer::isSafeAccess(ObjectSizeOffsetVisitor &ObjSizeVis,
34943496
Value *Addr, TypeSize TypeStoreSize) const {
3497+
if (TypeStoreSize.isScalable())
3498+
// TODO: We can use vscale_range to convert a scalable value to an
3499+
// upper bound on the access size.
3500+
return false;
34953501
SizeOffsetType SizeOffset = ObjSizeVis.compute(Addr);
34963502
if (!ObjSizeVis.bothKnown(SizeOffset)) return false;
34973503
uint64_t Size = SizeOffset.first.getZExtValue();

llvm/test/Instrumentation/AddressSanitizer/vector-load-store.ll

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,3 +947,67 @@ define void @store.nxv16i32(ptr %p) sanitize_address {
947947
ret void
948948
}
949949

950+
declare void @clobber(ptr)
951+
952+
define <vscale x 2 x i32> @local_alloca() sanitize_address {
953+
; CHECK-LABEL: @local_alloca(
954+
; CHECK-NEXT: [[A:%.*]] = alloca <vscale x 2 x i32>, align 8
955+
; CHECK-NEXT: call void @clobber(ptr [[A]])
956+
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.vscale.i64()
957+
; CHECK-NEXT: [[TMP2:%.*]] = mul i64 [[TMP1]], 64
958+
; CHECK-NEXT: [[TMP3:%.*]] = lshr i64 [[TMP2]], 3
959+
; CHECK-NEXT: [[TMP4:%.*]] = ptrtoint ptr [[A]] to i64
960+
; CHECK-NEXT: [[TMP5:%.*]] = sub i64 [[TMP3]], 1
961+
; CHECK-NEXT: [[TMP6:%.*]] = add i64 [[TMP4]], [[TMP5]]
962+
; CHECK-NEXT: [[TMP7:%.*]] = inttoptr i64 [[TMP6]] to ptr
963+
; CHECK-NEXT: [[TMP8:%.*]] = ptrtoint ptr [[A]] to i64
964+
; CHECK-NEXT: [[TMP9:%.*]] = lshr i64 [[TMP8]], 3
965+
; CHECK-NEXT: [[TMP10:%.*]] = or i64 [[TMP9]], 17592186044416
966+
; CHECK-NEXT: [[TMP11:%.*]] = inttoptr i64 [[TMP10]] to ptr
967+
; CHECK-NEXT: [[TMP12:%.*]] = load i8, ptr [[TMP11]], align 1
968+
; CHECK-NEXT: [[TMP13:%.*]] = icmp ne i8 [[TMP12]], 0
969+
; CHECK-NEXT: br i1 [[TMP13]], label [[TMP14:%.*]], label [[TMP19:%.*]], !prof [[PROF0]]
970+
; CHECK: 14:
971+
; CHECK-NEXT: [[TMP15:%.*]] = and i64 [[TMP8]], 7
972+
; CHECK-NEXT: [[TMP16:%.*]] = trunc i64 [[TMP15]] to i8
973+
; CHECK-NEXT: [[TMP17:%.*]] = icmp sge i8 [[TMP16]], [[TMP12]]
974+
; CHECK-NEXT: br i1 [[TMP17]], label [[TMP18:%.*]], label [[TMP19]]
975+
; CHECK: 18:
976+
; CHECK-NEXT: call void @__asan_report_load_n(i64 [[TMP8]], i64 [[TMP3]]) #[[ATTR4]]
977+
; CHECK-NEXT: unreachable
978+
; CHECK: 19:
979+
; CHECK-NEXT: [[TMP20:%.*]] = ptrtoint ptr [[TMP7]] to i64
980+
; CHECK-NEXT: [[TMP21:%.*]] = lshr i64 [[TMP20]], 3
981+
; CHECK-NEXT: [[TMP22:%.*]] = or i64 [[TMP21]], 17592186044416
982+
; CHECK-NEXT: [[TMP23:%.*]] = inttoptr i64 [[TMP22]] to ptr
983+
; CHECK-NEXT: [[TMP24:%.*]] = load i8, ptr [[TMP23]], align 1
984+
; CHECK-NEXT: [[TMP25:%.*]] = icmp ne i8 [[TMP24]], 0
985+
; CHECK-NEXT: br i1 [[TMP25]], label [[TMP26:%.*]], label [[TMP31:%.*]], !prof [[PROF0]]
986+
; CHECK: 26:
987+
; CHECK-NEXT: [[TMP27:%.*]] = and i64 [[TMP20]], 7
988+
; CHECK-NEXT: [[TMP28:%.*]] = trunc i64 [[TMP27]] to i8
989+
; CHECK-NEXT: [[TMP29:%.*]] = icmp sge i8 [[TMP28]], [[TMP24]]
990+
; CHECK-NEXT: br i1 [[TMP29]], label [[TMP30:%.*]], label [[TMP31]]
991+
; CHECK: 30:
992+
; CHECK-NEXT: call void @__asan_report_load_n(i64 [[TMP20]], i64 [[TMP3]]) #[[ATTR4]]
993+
; CHECK-NEXT: unreachable
994+
; CHECK: 31:
995+
; CHECK-NEXT: [[RES:%.*]] = load <vscale x 2 x i32>, ptr [[A]], align 8
996+
; CHECK-NEXT: ret <vscale x 2 x i32> [[RES]]
997+
;
998+
; CALLS-LABEL: @local_alloca(
999+
; CALLS-NEXT: [[A:%.*]] = alloca <vscale x 2 x i32>, align 8
1000+
; CALLS-NEXT: call void @clobber(ptr [[A]])
1001+
; CALLS-NEXT: [[TMP1:%.*]] = call i64 @llvm.vscale.i64()
1002+
; CALLS-NEXT: [[TMP2:%.*]] = mul i64 [[TMP1]], 64
1003+
; CALLS-NEXT: [[TMP3:%.*]] = lshr i64 [[TMP2]], 3
1004+
; CALLS-NEXT: [[TMP4:%.*]] = ptrtoint ptr [[A]] to i64
1005+
; CALLS-NEXT: call void @__asan_loadN(i64 [[TMP4]], i64 [[TMP3]])
1006+
; CALLS-NEXT: [[RES:%.*]] = load <vscale x 2 x i32>, ptr [[A]], align 8
1007+
; CALLS-NEXT: ret <vscale x 2 x i32> [[RES]]
1008+
;
1009+
%a = alloca <vscale x 2 x i32>
1010+
call void @clobber(ptr %a)
1011+
%res = load <vscale x 2 x i32>, ptr %a
1012+
ret <vscale x 2 x i32> %res
1013+
}

0 commit comments

Comments
 (0)