Skip to content

Commit 58a81c6

Browse files
committedSep 8, 2016
[asan] Avoid lifetime analysis for allocas with can be in ambiguous state
Summary: C allows to jump over variables declaration so lifetime.start can be avoid before variable usage. To avoid false-positives on such rare cases we detect them and remove from lifetime analysis. PR27453 PR28267 Reviewers: eugenis Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D24321 llvm-svn: 280907
1 parent 0b4c26b commit 58a81c6

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed
 

‎llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp

+75
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,77 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> {
833833
Instruction *ThenTerm, Value *ValueIfFalse);
834834
};
835835

836+
// Performs depth-first search on the control flow graph of block and checks if
837+
// we can get into the same block with different lifetime state.
838+
class AllocaLifetimeChecker {
839+
// Contains values of the last lifetime intrinsics in the block.
840+
// true: llvm.lifetime.start, false: llvm.lifetime.end
841+
DenseMap<const BasicBlock *, bool> Markers;
842+
// Contains the lifetime state we detected doing depth-first search on the
843+
// control flow graph. We expect all future hits will have the same value.
844+
// true: llvm.lifetime.start, false: llvm.lifetime.end
845+
DenseMap<const BasicBlock *, bool> InboundState;
846+
bool Processed = false;
847+
bool CollisionDetected = false;
848+
849+
bool FindCollision(const std::pair<const BasicBlock *, bool> &BlockState) {
850+
auto Ins = InboundState.insert(BlockState);
851+
if (!Ins.second) {
852+
// Already there. Return collision if they are different.
853+
return BlockState.second != Ins.first->second;
854+
}
855+
856+
// Use marker for successors if block contains any.
857+
auto M = Markers.find(BlockState.first);
858+
bool NewState = (M != Markers.end() ? M->second : BlockState.second);
859+
for (const BasicBlock *SB : successors(BlockState.first))
860+
// We may get into EHPad with any lifetime state, so ignore them.
861+
if (!SB->isEHPad() && FindCollision({SB, NewState}))
862+
return true;
863+
864+
return false;
865+
}
866+
867+
public:
868+
// Assume that markers of the same block will be added in the same order as
869+
// the order of corresponding intrinsics, so in the end we will keep only
870+
// value of the last intrinsic.
871+
void AddMarker(const BasicBlock *BB, bool start) {
872+
assert(!Processed);
873+
Markers[BB] = start;
874+
}
875+
876+
bool HasAmbiguousLifetime() {
877+
if (!Processed) {
878+
Processed = true;
879+
const Function *F = Markers.begin()->first->getParent();
880+
CollisionDetected = FindCollision({&F->getEntryBlock(), false});
881+
}
882+
return CollisionDetected;
883+
}
884+
};
885+
886+
// Removes allocas for which exists at least one block simultaneously
887+
// reachable in both states: allocas is inside the scope, and alloca is outside
888+
// of the scope. We don't have enough information to validate access to such
889+
// variable, so we just remove such allocas from lifetime analysis.
890+
// This is workaround for PR28267.
891+
void removeAllocasWithAmbiguousLifetime(
892+
SmallVectorImpl<FunctionStackPoisoner::AllocaPoisonCall> &PoisonCallVec) {
893+
DenseMap<const AllocaInst *, AllocaLifetimeChecker> Checkers;
894+
for (const auto &APC : PoisonCallVec)
895+
Checkers[APC.AI].AddMarker(APC.InsBefore->getParent(), !APC.DoPoison);
896+
897+
auto IsAmbiguous =
898+
[&Checkers](const FunctionStackPoisoner::AllocaPoisonCall &APC) {
899+
return Checkers[APC.AI].HasAmbiguousLifetime();
900+
};
901+
902+
PoisonCallVec.erase(
903+
std::remove_if(PoisonCallVec.begin(), PoisonCallVec.end(), IsAmbiguous),
904+
PoisonCallVec.end());
905+
}
906+
836907
} // anonymous namespace
837908

838909
char AddressSanitizer::ID = 0;
@@ -2110,6 +2181,8 @@ void FunctionStackPoisoner::processDynamicAllocas() {
21102181
return;
21112182
}
21122183

2184+
removeAllocasWithAmbiguousLifetime(DynamicAllocaPoisonCallVec);
2185+
21132186
// Insert poison calls for lifetime intrinsics for dynamic allocas.
21142187
for (const auto &APC : DynamicAllocaPoisonCallVec) {
21152188
assert(APC.InsBefore);
@@ -2137,6 +2210,8 @@ void FunctionStackPoisoner::processStaticAllocas() {
21372210
return;
21382211
}
21392212

2213+
removeAllocasWithAmbiguousLifetime(StaticAllocaPoisonCallVec);
2214+
21402215
int StackMallocIdx = -1;
21412216
DebugLoc EntryDebugLocation;
21422217
if (auto SP = F.getSubprogram())

‎llvm/test/Instrumentation/AddressSanitizer/lifetime.ll

+41
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,47 @@ define void @lifetime() sanitize_address {
9797
ret void
9898
}
9999

100+
; Case of lifetime depends on how we get into the block.
101+
define void @ambiguous_lifetime(i1 %x) sanitize_address {
102+
; CHECK-LABEL: define void @ambiguous_lifetime
103+
104+
entry:
105+
; Regular variable lifetime intrinsics.
106+
%i = alloca i8, align 4 ; Good
107+
%j = alloca i8, align 4 ; Bad
108+
109+
call void @llvm.lifetime.start(i64 1, i8* %i)
110+
; CHECK: store i8 1, i8* %{{[0-9]+}}
111+
; CHECK-NEXT: call void @llvm.lifetime.start
112+
113+
br i1 %x, label %bb0, label %bb1
114+
115+
bb0:
116+
; CHECK-LABEL: bb0:
117+
118+
call void @llvm.lifetime.start(i64 1, i8* %j)
119+
; CHECK-NOT: store i8 1, i8* %{{[0-9]+}}
120+
; CHECK-NEXT: call void @llvm.lifetime.start
121+
122+
br label %bb1
123+
124+
bb1:
125+
; CHECK-LABEL: bb1:
126+
127+
store volatile i8 0, i8* %i
128+
store volatile i8 0, i8* %j
129+
130+
call void @llvm.lifetime.end(i64 1, i8* %i)
131+
; CHECK: store i8 -8, i8* %{{[0-9]+}}
132+
; CHECK-NEXT: call void @llvm.lifetime.end
133+
134+
call void @llvm.lifetime.end(i64 1, i8* %j)
135+
; CHECK-NOT: store i8 -8, i8* %{{[0-9]+}}
136+
; CHECK-NEXT: call void @llvm.lifetime.end
137+
138+
ret void
139+
}
140+
100141
; Check that arguments of lifetime may come from phi nodes.
101142
define void @phi_args(i1 %x) sanitize_address {
102143
; CHECK-LABEL: define void @phi_args(i1 %x)

0 commit comments

Comments
 (0)
Please sign in to comment.