Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit d73e0d8

Browse files
[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
1 parent ff323c3 commit d73e0d8

File tree

3 files changed

+67
-4
lines changed

3 files changed

+67
-4
lines changed

include/llvm/Analysis/PhiValues.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,22 @@ class PhiValues {
8888
/// All values reachable from each component.
8989
DenseMap<unsigned int, ConstValueSet> ReachableMap;
9090

91+
/// A CallbackVH to notify PhiValues when a value is deleted or replaced, so
92+
/// that the cached information for that value can be cleared to avoid
93+
/// dangling pointers to invalid values.
94+
class PhiValuesCallbackVH final : public CallbackVH {
95+
PhiValues *PV;
96+
void deleted() override;
97+
void allUsesReplacedWith(Value *New) override;
98+
99+
public:
100+
PhiValuesCallbackVH(Value *V, PhiValues *PV = nullptr)
101+
: CallbackVH(V), PV(PV) {}
102+
};
103+
104+
/// A set of callbacks to the values that processPhi has seen.
105+
DenseSet<PhiValuesCallbackVH, DenseMapInfo<Value *>> TrackedValues;
106+
91107
/// The function that the PhiValues is for.
92108
const Function &F;
93109

lib/Analysis/PhiValues.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@
1414

1515
using namespace llvm;
1616

17+
void PhiValues::PhiValuesCallbackVH::deleted() {
18+
PV->invalidateValue(getValPtr());
19+
}
20+
21+
void PhiValues::PhiValuesCallbackVH::allUsesReplacedWith(Value *) {
22+
// We could potentially update the cached values we have with the new value,
23+
// but it's simpler to just treat the old value as invalidated.
24+
PV->invalidateValue(getValPtr());
25+
}
26+
1727
bool PhiValues::invalidate(Function &, const PreservedAnalyses &PA,
1828
FunctionAnalysisManager::Invalidator &) {
1929
// PhiValues is invalidated if it isn't preserved.
@@ -46,6 +56,7 @@ void PhiValues::processPhi(const PHINode *Phi,
4656
DepthMap[Phi] = DepthNumber;
4757

4858
// Recursively process the incoming phis of this phi.
59+
TrackedValues.insert(PhiValuesCallbackVH(const_cast<PHINode *>(Phi), this));
4960
for (Value *PhiOp : Phi->incoming_values()) {
5061
if (PHINode *PhiPhiOp = dyn_cast<PHINode>(PhiOp)) {
5162
// Recurse if the phi has not yet been visited.
@@ -56,6 +67,8 @@ void PhiValues::processPhi(const PHINode *Phi,
5667
// phi are part of the same component, so adjust the depth number.
5768
if (!ReachableMap.count(DepthMap[PhiPhiOp]))
5869
DepthMap[Phi] = std::min(DepthMap[Phi], DepthMap[PhiPhiOp]);
70+
} else {
71+
TrackedValues.insert(PhiValuesCallbackVH(PhiOp, this));
5972
}
6073
}
6174

@@ -122,6 +135,10 @@ void PhiValues::invalidateValue(const Value *V) {
122135
NonPhiReachableMap.erase(N);
123136
ReachableMap.erase(N);
124137
}
138+
// This value is no longer tracked
139+
auto It = TrackedValues.find_as(V);
140+
if (It != TrackedValues.end())
141+
TrackedValues.erase(It);
125142
}
126143

127144
void PhiValues::releaseMemory() {

test/Analysis/BasicAA/phi-values-usage.ll

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
1-
; RUN: opt -debug-pass=Executions -phi-values -memcpyopt -instcombine -disable-output < %s 2>&1 | FileCheck %s
1+
; RUN: opt -debug-pass=Executions -phi-values -memcpyopt -instcombine -disable-output < %s 2>&1 | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-MEMCPY
2+
; RUN: opt -debug-pass=Executions -memdep -instcombine -disable-output < %s 2>&1 | FileCheck %s -check-prefix=CHECK
23

34
; Check that phi values is not run when it's not already available, and that
45
; basicaa is freed after a pass that preserves CFG.
56

67
; CHECK: Executing Pass 'Phi Values Analysis'
78
; CHECK: Executing Pass 'Basic Alias Analysis (stateless AA impl)'
89
; CHECK: Executing Pass 'Memory Dependence Analysis'
9-
; CHECK: Executing Pass 'MemCpy Optimization'
10-
; CHECK-DAG: Freeing Pass 'MemCpy Optimization'
10+
; CHECK-MEMCPY: Executing Pass 'MemCpy Optimization'
11+
; CHECK-MEMCPY-DAG: Freeing Pass 'MemCpy Optimization'
1112
; CHECK-DAG: Freeing Pass 'Phi Values Analysis'
1213
; CHECK-DAG: Freeing Pass 'Memory Dependence Analysis'
1314
; CHECK-DAG: Freeing Pass 'Basic Alias Analysis (stateless AA impl)'
1415
; CHECK-NOT: Executing Pass 'Phi Values Analysis'
15-
; CHECK: Executing Pass 'Basic Alias Analysis (stateless AA impl)'
16+
; CHECK-MEMCPY: Executing Pass 'Basic Alias Analysis (stateless AA impl)'
1617
; CHECK: Executing Pass 'Combine redundant instructions'
1718

19+
target datalayout = "p:8:8-n8"
20+
1821
declare void @otherfn([4 x i8]*)
1922
declare i32 @__gxx_personality_v0(...)
23+
declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
24+
@c = external global i8*, align 1
2025

2126
; This function is one where if we didn't free basicaa after memcpyopt then the
2227
; usage of basicaa in instcombine would cause a segfault due to stale phi-values
@@ -48,3 +53,28 @@ lpad:
4853
call void @otherfn([4 x i8]* nonnull %arr)
4954
unreachable
5055
}
56+
57+
; When running instcombine after memdep, the basicaa used by instcombine uses
58+
; the phivalues that memdep used. This would then cause a segfault due to
59+
; instcombine deleting a phi whose values had been cached.
60+
define void @fn2() {
61+
entry:
62+
%a = alloca i8, align 1
63+
%0 = load i8*, i8** @c, align 1
64+
%1 = bitcast i8* %0 to i8**
65+
br label %for.cond
66+
67+
for.cond: ; preds = %for.body, %entry
68+
%d.0 = phi i8** [ %1, %entry ], [ null, %for.body ]
69+
br i1 undef, label %for.body, label %for.cond.cleanup
70+
71+
for.body: ; preds = %for.cond
72+
store volatile i8 undef, i8* %a, align 1
73+
br label %for.cond
74+
75+
for.cond.cleanup: ; preds = %for.cond
76+
call void @llvm.lifetime.end.p0i8(i64 1, i8* %a)
77+
%2 = load i8*, i8** %d.0, align 1
78+
store i8* %2, i8** @c, align 1
79+
ret void
80+
}

0 commit comments

Comments
 (0)