llvm.org GIT mirror llvm / d73e0d8
[PhiValues] Use callback value handles to invalidate deleted values The way that PhiValues is integrated with BasicAA it is possible for a pass which uses BasicAA to pick up an instance of BasicAA that uses PhiValues without intending to, and then delete values from a function in a way that causes PhiValues to return dangling pointers to these deleted values. Fix this by having a set of callback value handles to invalidate values when they're deleted. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@340613 91177308-0d34-0410-b5e6-96231b3b80d8 John Brawn 1 year, 9 months ago
3 changed file(s) with 67 addition(s) and 4 deletion(s). Raw diff Collapse all Expand all
8787 /// All values reachable from each component.
8888 DenseMap ReachableMap;
8989
90 /// A CallbackVH to notify PhiValues when a value is deleted or replaced, so
91 /// that the cached information for that value can be cleared to avoid
92 /// dangling pointers to invalid values.
93 class PhiValuesCallbackVH final : public CallbackVH {
94 PhiValues *PV;
95 void deleted() override;
96 void allUsesReplacedWith(Value *New) override;
97
98 public:
99 PhiValuesCallbackVH(Value *V, PhiValues *PV = nullptr)
100 : CallbackVH(V), PV(PV) {}
101 };
102
103 /// A set of callbacks to the values that processPhi has seen.
104 DenseSet> TrackedValues;
105
90106 /// The function that the PhiValues is for.
91107 const Function &F;
92108
1212 #include "llvm/IR/Instructions.h"
1313
1414 using namespace llvm;
15
16 void PhiValues::PhiValuesCallbackVH::deleted() {
17 PV->invalidateValue(getValPtr());
18 }
19
20 void PhiValues::PhiValuesCallbackVH::allUsesReplacedWith(Value *) {
21 // We could potentially update the cached values we have with the new value,
22 // but it's simpler to just treat the old value as invalidated.
23 PV->invalidateValue(getValPtr());
24 }
1525
1626 bool PhiValues::invalidate(Function &, const PreservedAnalyses &PA,
1727 FunctionAnalysisManager::Invalidator &) {
4555 DepthMap[Phi] = DepthNumber;
4656
4757 // Recursively process the incoming phis of this phi.
58 TrackedValues.insert(PhiValuesCallbackVH(const_cast(Phi), this));
4859 for (Value *PhiOp : Phi->incoming_values()) {
4960 if (PHINode *PhiPhiOp = dyn_cast(PhiOp)) {
5061 // Recurse if the phi has not yet been visited.
5566 // phi are part of the same component, so adjust the depth number.
5667 if (!ReachableMap.count(DepthMap[PhiPhiOp]))
5768 DepthMap[Phi] = std::min(DepthMap[Phi], DepthMap[PhiPhiOp]);
69 } else {
70 TrackedValues.insert(PhiValuesCallbackVH(PhiOp, this));
5871 }
5972 }
6073
121134 NonPhiReachableMap.erase(N);
122135 ReachableMap.erase(N);
123136 }
137 // This value is no longer tracked
138 auto It = TrackedValues.find_as(V);
139 if (It != TrackedValues.end())
140 TrackedValues.erase(It);
124141 }
125142
126143 void PhiValues::releaseMemory() {
None ; RUN: opt -debug-pass=Executions -phi-values -memcpyopt -instcombine -disable-output < %s 2>&1 | FileCheck %s
0 ; RUN: opt -debug-pass=Executions -phi-values -memcpyopt -instcombine -disable-output < %s 2>&1 | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-MEMCPY
1 ; RUN: opt -debug-pass=Executions -memdep -instcombine -disable-output < %s 2>&1 | FileCheck %s -check-prefix=CHECK
12
23 ; Check that phi values is not run when it's not already available, and that
34 ; basicaa is freed after a pass that preserves CFG.
56 ; CHECK: Executing Pass 'Phi Values Analysis'
67 ; CHECK: Executing Pass 'Basic Alias Analysis (stateless AA impl)'
78 ; CHECK: Executing Pass 'Memory Dependence Analysis'
8 ; CHECK: Executing Pass 'MemCpy Optimization'
9 ; CHECK-DAG: Freeing Pass 'MemCpy Optimization'
9 ; CHECK-MEMCPY: Executing Pass 'MemCpy Optimization'
10 ; CHECK-MEMCPY-DAG: Freeing Pass 'MemCpy Optimization'
1011 ; CHECK-DAG: Freeing Pass 'Phi Values Analysis'
1112 ; CHECK-DAG: Freeing Pass 'Memory Dependence Analysis'
1213 ; CHECK-DAG: Freeing Pass 'Basic Alias Analysis (stateless AA impl)'
1314 ; CHECK-NOT: Executing Pass 'Phi Values Analysis'
14 ; CHECK: Executing Pass 'Basic Alias Analysis (stateless AA impl)'
15 ; CHECK-MEMCPY: Executing Pass 'Basic Alias Analysis (stateless AA impl)'
1516 ; CHECK: Executing Pass 'Combine redundant instructions'
17
18 target datalayout = "p:8:8-n8"
1619
1720 declare void @otherfn([4 x i8]*)
1821 declare i32 @__gxx_personality_v0(...)
22 declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
23 @c = external global i8*, align 1
1924
2025 ; This function is one where if we didn't free basicaa after memcpyopt then the
2126 ; usage of basicaa in instcombine would cause a segfault due to stale phi-values
4752 call void @otherfn([4 x i8]* nonnull %arr)
4853 unreachable
4954 }
55
56 ; When running instcombine after memdep, the basicaa used by instcombine uses
57 ; the phivalues that memdep used. This would then cause a segfault due to
58 ; instcombine deleting a phi whose values had been cached.
59 define void @fn2() {
60 entry:
61 %a = alloca i8, align 1
62 %0 = load i8*, i8** @c, align 1
63 %1 = bitcast i8* %0 to i8**
64 br label %for.cond
65
66 for.cond: ; preds = %for.body, %entry
67 %d.0 = phi i8** [ %1, %entry ], [ null, %for.body ]
68 br i1 undef, label %for.body, label %for.cond.cleanup
69
70 for.body: ; preds = %for.cond
71 store volatile i8 undef, i8* %a, align 1
72 br label %for.cond
73
74 for.cond.cleanup: ; preds = %for.cond
75 call void @llvm.lifetime.end.p0i8(i64 1, i8* %a)
76 %2 = load i8*, i8** %d.0, align 1
77 store i8* %2, i8** @c, align 1
78 ret void
79 }