-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathRangeSSA.qll
More file actions
168 lines (149 loc) · 5.77 KB
/
RangeSSA.qll
File metadata and controls
168 lines (149 loc) · 5.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/**
* This library is a clone of semmle.code.cpp.controlflow.SSA, with
* only one difference: extra phi definitions are added after
* guards. For example:
* ```
* x = f();
* if (x < 10) {
* // Block 1
* ...
* } else {
* // Block 2
* ...
* }
* ```
* In standard SSA, basic blocks 1 and 2 do not need phi definitions
* for `x`, because they are dominated by the definition of `x` on the
* first line. In RangeSSA, however, we add phi definitions for `x` at
* the beginning of blocks 1 and 2. This is useful for range analysis
* because it enables us to deduce a more accurate range for `x` in the
* two branches of the if-statement.
*/
import cpp
import semmle.code.cpp.controlflow.Dominance
import semmle.code.cpp.controlflow.SSAUtils
private import RangeAnalysisUtils
/**
* The SSA logic comes in two versions: the standard SSA and range-analysis RangeSSA.
* This class provides the range-analysis SSA logic.
*/
class RangeSsa extends SsaHelper {
RangeSsa() { this = 1 }
/**
* Add a phi node on the out-edge of a guard.
*/
override predicate custom_phi_node(StackVariable v, BasicBlock b) {
guard_defn(v.getAnAccess(), _, b, _)
}
}
private predicate guard_defn(VariableAccess v, Expr guard, BasicBlock b, boolean branch) {
guardCondition(guard, v, branch) and
guardSuccessor(guard, branch, b)
}
private predicate guardCondition(Expr guard, VariableAccess v, boolean branch) {
exists(Expr lhs | linearAccess(lhs, v, _, _) |
relOpWithSwapAndNegate(guard, lhs, _, _, _, branch) or
eqOpWithSwapAndNegate(guard, lhs, _, _, branch) or
eqZeroWithNegate(guard, lhs, _, branch)
)
}
private predicate guardSuccessor(Expr guard, boolean branch, BasicBlock succ) {
branch = true and succ = guard.getATrueSuccessor()
or
branch = false and succ = guard.getAFalseSuccessor()
}
/**
* A definition of one or more SSA variables, including phi node
* definitions. An SSA variable is effectively the pair of a definition
* and the (non-SSA) variable that it defines. Note definitions and uses
* can be coincident, due to the presence of parameter definitions and phi
* nodes.
*/
class RangeSsaDefinition extends ControlFlowNodeBase {
RangeSsaDefinition() { exists(RangeSsa x | x.ssa_defn(_, this, _, _)) }
/**
* Gets a variable corresponding to a SSA StackVariable defined by
* this definition.
*/
StackVariable getAVariable() { exists(RangeSsa x | x.ssa_defn(result, this, _, _)) }
/**
* A string representation of the SSA variable represented by the pair
* `(this, v)`.
*/
string toString(StackVariable v) { exists(RangeSsa x | result = x.toString(this, v)) }
/** Gets a use of the SSA variable represented by the pair `(this, v)`. */
VariableAccess getAUse(StackVariable v) { exists(RangeSsa x | result = x.getAUse(this, v)) }
/** Gets the control flow node for this definition. */
ControlFlowNode getDefinition() { result = this }
/** Gets the basic block containing this definition. */
BasicBlock getBasicBlock() { result.contains(this.getDefinition()) }
/** Whether this definition is a phi node for variable `v`. */
predicate isPhiNode(StackVariable v) { exists(RangeSsa x | x.phi_node(v, this)) }
/**
* If this definition is a phi node corresponding to a guard,
* then return the variable guarded, the variable access and the guard.
*/
predicate isGuardPhi(StackVariable v, VariableAccess va, Expr guard, boolean branch) {
guard_defn(va, guard, this, branch) and
va.getTarget() = v
}
/** Gets the primary location of this definition. */
Location getLocation() { result = this.(ControlFlowNode).getLocation() }
/** Whether this definition is from a parameter */
predicate definedByParameter(Parameter p) { this = p.getFunction().getEntryPoint() }
/** Gets a definition of `v` that is a phi input for this basic block. */
RangeSsaDefinition getAPhiInput(StackVariable v) {
this.isPhiNode(v) and
exists(BasicBlock pred |
pred = this.(BasicBlock).getAPredecessor() and
result.reachesEndOfBB(v, pred) and
// Suppose we have a CFG like this:
//
// 1: x_0 = <expr>;
// 2: if (<cond>) {
// 3: if (x_0 > 1) {
// 4: x_1 = phi(x_0);
// 5: }
// 6: }
// 7: x_2 = phi(x_0, x_1);
//
// The phi nodes on lines 4 and 7 are both guard phi nodes,
// because they have an incoming edge from the condition on
// line 3. Definition x_0 on line 1 should be considered a
// phi-input on line 7, but not on line 4. This is because
// the only CFG path from line 1 to line 4 goes through the
// condition on line 3, but there is a path from line 1 to
// line 7 which does not go through the condition. The logic
// below excludes definitions which can only reach guard phi
// nodes by going through the corresponding guard.
not exists(VariableAccess access |
pred.contains(access) and
this.isGuardPhi(v, access, _, _)
)
)
}
/** Gets the expression assigned to this SsaDefinition. */
Expr getDefiningValue(StackVariable v) {
exists(ControlFlowNode def | def = this.getDefinition() |
def = v.getInitializer().getExpr() and def = result
or
exists(AssignExpr assign |
def = assign and
assign.getLValue() = v.getAnAccess() and
result = assign.getRValue()
)
or
exists(AssignOperation assign |
def = assign and
assign.getLValue() = v.getAnAccess() and
result = assign
)
)
}
/**
* Holds if this definition of the variable `v` reached the end of the basic block `b`.
*/
predicate reachesEndOfBB(StackVariable v, BasicBlock b) {
exists(RangeSsa x | x.ssaDefinitionReachesEndOfBB(v, this, b))
}
}