@@ -833,6 +833,77 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> {
833
833
Instruction *ThenTerm, Value *ValueIfFalse);
834
834
};
835
835
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
+
836
907
} // anonymous namespace
837
908
838
909
char AddressSanitizer::ID = 0 ;
@@ -2110,6 +2181,8 @@ void FunctionStackPoisoner::processDynamicAllocas() {
2110
2181
return ;
2111
2182
}
2112
2183
2184
+ removeAllocasWithAmbiguousLifetime (DynamicAllocaPoisonCallVec);
2185
+
2113
2186
// Insert poison calls for lifetime intrinsics for dynamic allocas.
2114
2187
for (const auto &APC : DynamicAllocaPoisonCallVec) {
2115
2188
assert (APC.InsBefore );
@@ -2137,6 +2210,8 @@ void FunctionStackPoisoner::processStaticAllocas() {
2137
2210
return ;
2138
2211
}
2139
2212
2213
+ removeAllocasWithAmbiguousLifetime (StaticAllocaPoisonCallVec);
2214
+
2140
2215
int StackMallocIdx = -1 ;
2141
2216
DebugLoc EntryDebugLocation;
2142
2217
if (auto SP = F.getSubprogram ())
0 commit comments