Skip to content

Commit 95a333d

Browse files
committed
C++: Use StackVariable in SSA libraries
This means we'll no longer get SSA definitions for thread-local local-scope variables.
1 parent c1ed908 commit 95a333d

File tree

16 files changed

+61
-76
lines changed

16 files changed

+61
-76
lines changed

cpp/ql/src/semmle/code/cpp/controlflow/SSA.qll

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ library class StandardSSA extends SSAHelper {
99
/**
1010
* A definition of one or more SSA variables, including phi node definitions.
1111
* An _SSA variable_, as defined in the literature, is effectively the pair of
12-
* an `SsaDefinition d` and a `LocalScopeVariable v`, written `(d, v)` in this
12+
* an `SsaDefinition d` and a `StackVariable v`, written `(d, v)` in this
1313
* documentation. Note that definitions and uses can be coincident due to the
1414
* presence of parameter definitions and phi nodes.
1515
*
16-
* Not all `LocalScopeVariable`s of a function have SSA definitions. If the variable
16+
* Not all `StackVariable`s of a function have SSA definitions. If the variable
1717
* has its address taken, either explicitly or implicitly, then it is excluded
1818
* from analysis. `SsaDefinition`s are not generated in locations that are
1919
* statically seen to be unreachable.
@@ -22,21 +22,19 @@ class SsaDefinition extends ControlFlowNodeBase {
2222
SsaDefinition() { exists(StandardSSA x | x.ssa_defn(_, this, _, _)) }
2323

2424
/**
25-
* Gets a variable corresponding to an SSA LocalScopeVariable defined by
25+
* Gets a variable corresponding to an SSA StackVariable defined by
2626
* this definition.
2727
*/
28-
LocalScopeVariable getAVariable() { exists(StandardSSA x | x.ssa_defn(result, this, _, _)) }
28+
StackVariable getAVariable() { exists(StandardSSA x | x.ssa_defn(result, this, _, _)) }
2929

3030
/**
3131
* Gets a string representation of the SSA variable represented by the pair
3232
* `(this, v)`.
3333
*/
34-
string toString(LocalScopeVariable v) { exists(StandardSSA x | result = x.toString(this, v)) }
34+
string toString(StackVariable v) { exists(StandardSSA x | result = x.toString(this, v)) }
3535

3636
/** Gets a use of the SSA variable represented by the pair `(this, v)`. */
37-
VariableAccess getAUse(LocalScopeVariable v) {
38-
exists(StandardSSA x | result = x.getAUse(this, v))
39-
}
37+
VariableAccess getAUse(StackVariable v) { exists(StandardSSA x | result = x.getAUse(this, v)) }
4038

4139
/**
4240
* Gets the control-flow node for this definition. This will usually be the
@@ -55,9 +53,7 @@ class SsaDefinition extends ControlFlowNodeBase {
5553
BasicBlock getBasicBlock() { result.contains(getDefinition()) }
5654

5755
/** Holds if this definition is a phi node for variable `v`. */
58-
predicate isPhiNode(LocalScopeVariable v) {
59-
exists(StandardSSA x | x.phi_node(v, this.(BasicBlock)))
60-
}
56+
predicate isPhiNode(StackVariable v) { exists(StandardSSA x | x.phi_node(v, this.(BasicBlock))) }
6157

6258
Location getLocation() { result = this.(ControlFlowNode).getLocation() }
6359

@@ -68,7 +64,7 @@ class SsaDefinition extends ControlFlowNodeBase {
6864
* Holds if the SSA variable `(result, v)` is an input to the phi definition
6965
* `(this, v)`.
7066
*/
71-
SsaDefinition getAPhiInput(LocalScopeVariable v) {
67+
SsaDefinition getAPhiInput(StackVariable v) {
7268
this.isPhiNode(v) and
7369
result.reachesEndOfBB(v, this.(BasicBlock).getAPredecessor())
7470
}
@@ -92,7 +88,7 @@ class SsaDefinition extends ControlFlowNodeBase {
9288
* instead covered via `definedByParameter` and `getDefinition`,
9389
* respectively.
9490
*/
95-
Expr getDefiningValue(LocalScopeVariable v) {
91+
Expr getDefiningValue(StackVariable v) {
9692
exists(ControlFlowNode def | def = this.getDefinition() |
9793
def = v.getInitializer().getExpr() and def = result
9894
or
@@ -117,15 +113,15 @@ class SsaDefinition extends ControlFlowNodeBase {
117113
}
118114

119115
/** Holds if `(this, v)` reaches the end of basic block `b`. */
120-
predicate reachesEndOfBB(LocalScopeVariable v, BasicBlock b) {
116+
predicate reachesEndOfBB(StackVariable v, BasicBlock b) {
121117
exists(StandardSSA x | x.ssaDefinitionReachesEndOfBB(v, this, b))
122118
}
123119

124120
/**
125121
* Gets a definition that ultimately defines this variable and is not
126122
* itself a phi node.
127123
*/
128-
SsaDefinition getAnUltimateSsaDefinition(LocalScopeVariable v) {
124+
SsaDefinition getAnUltimateSsaDefinition(StackVariable v) {
129125
result = this.getAPhiInput(v).getAnUltimateSsaDefinition(v)
130126
or
131127
v = this.getAVariable() and
@@ -138,7 +134,7 @@ class SsaDefinition extends ControlFlowNodeBase {
138134
* recursing backwards through phi definitions. Not all definitions have a
139135
* defining expression---see the documentation for `getDefiningValue`.
140136
*/
141-
Expr getAnUltimateDefiningValue(LocalScopeVariable v) {
137+
Expr getAnUltimateDefiningValue(StackVariable v) {
142138
result = this.getAnUltimateSsaDefinition(v).getDefiningValue(v)
143139
}
144140

@@ -149,7 +145,7 @@ class SsaDefinition extends ControlFlowNodeBase {
149145
* `getAnUltimateSsaDefinition` to refer to a predicate named
150146
* `getAnUltimateSsaDefinition` in this class.
151147
*/
152-
deprecated Expr getAnUltimateDefinition(LocalScopeVariable v) {
148+
deprecated Expr getAnUltimateDefinition(StackVariable v) {
153149
result = this.getAnUltimateDefiningValue(v)
154150
}
155151
}

cpp/ql/src/semmle/code/cpp/controlflow/SSAUtils.qll

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,9 @@ private predicate dominanceFrontier(BasicBlock x, BasicBlock w) {
2121
}
2222

2323
/**
24-
* Extended version of `definition` that also includes parameters but excludes
25-
* static variables.
24+
* Extended version of `definition` that also includes parameters.
2625
*/
27-
predicate var_definition(LocalScopeVariable v, ControlFlowNode node) {
28-
not v.isStatic() and
26+
predicate var_definition(StackVariable v, ControlFlowNode node) {
2927
not addressTakenVariable(v) and
3028
not unreachable(node) and
3129
(
@@ -51,7 +49,7 @@ predicate var_definition(LocalScopeVariable v, ControlFlowNode node) {
5149
* analysis because the pointer could be used to change the value at
5250
* any moment.
5351
*/
54-
private predicate addressTakenVariable(LocalScopeVariable var) {
52+
private predicate addressTakenVariable(StackVariable var) {
5553
// If the type of the variable is a reference type, then it is safe (as
5654
// far as SSA is concerned) to take its address, because this does not
5755
// enable the variable to be modified indirectly. Obviously the
@@ -71,30 +69,30 @@ private predicate addressTakenVariable(LocalScopeVariable var) {
7169
)
7270
}
7371

74-
private predicate isReferenceVar(LocalScopeVariable v) {
72+
private predicate isReferenceVar(StackVariable v) {
7573
v.getUnspecifiedType() instanceof ReferenceType
7674
}
7775

7876
/**
7977
* This predicate is the same as `var_definition`, but annotated with
8078
* the basic block and index of the control flow node.
8179
*/
82-
private predicate variableUpdate(LocalScopeVariable v, ControlFlowNode n, BasicBlock b, int i) {
80+
private predicate variableUpdate(StackVariable v, ControlFlowNode n, BasicBlock b, int i) {
8381
var_definition(v, n) and n = b.getNode(i)
8482
}
8583

86-
private predicate ssa_use(LocalScopeVariable v, VariableAccess node, BasicBlock b, int index) {
84+
private predicate ssa_use(StackVariable v, VariableAccess node, BasicBlock b, int index) {
8785
useOfVar(v, node) and b.getNode(index) = node
8886
}
8987

90-
private predicate live_at_start_of_bb(LocalScopeVariable v, BasicBlock b) {
88+
private predicate live_at_start_of_bb(StackVariable v, BasicBlock b) {
9189
exists(int i | ssa_use(v, _, b, i) | not exists(int j | variableUpdate(v, _, b, j) | j < i))
9290
or
9391
live_at_exit_of_bb(v, b) and not variableUpdate(v, _, b, _)
9492
}
9593

9694
pragma[noinline]
97-
private predicate live_at_exit_of_bb(LocalScopeVariable v, BasicBlock b) {
95+
private predicate live_at_exit_of_bb(StackVariable v, BasicBlock b) {
9896
live_at_start_of_bb(v, b.getASuccessor())
9997
}
10098

@@ -110,12 +108,12 @@ library class SSAHelper extends int {
110108
* basic block `b`.
111109
*/
112110
cached
113-
predicate custom_phi_node(LocalScopeVariable v, BasicBlock b) { none() }
111+
predicate custom_phi_node(StackVariable v, BasicBlock b) { none() }
114112

115113
/**
116114
* Remove any custom phi nodes that are invalid.
117115
*/
118-
private predicate sanitized_custom_phi_node(LocalScopeVariable v, BasicBlock b) {
116+
private predicate sanitized_custom_phi_node(StackVariable v, BasicBlock b) {
119117
custom_phi_node(v, b) and
120118
not addressTakenVariable(v) and
121119
not isReferenceVar(v) and
@@ -127,7 +125,7 @@ library class SSAHelper extends int {
127125
* `b`.
128126
*/
129127
cached
130-
predicate phi_node(LocalScopeVariable v, BasicBlock b) {
128+
predicate phi_node(StackVariable v, BasicBlock b) {
131129
frontier_phi_node(v, b) or sanitized_custom_phi_node(v, b)
132130
}
133131

@@ -138,13 +136,13 @@ library class SSAHelper extends int {
138136
* definitions). This is known as the iterated dominance frontier. See
139137
* Modern Compiler Implementation by Andrew Appel.
140138
*/
141-
private predicate frontier_phi_node(LocalScopeVariable v, BasicBlock b) {
139+
private predicate frontier_phi_node(StackVariable v, BasicBlock b) {
142140
exists(BasicBlock x | dominanceFrontier(x, b) and ssa_defn_rec(v, x)) and
143141
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
144142
live_at_start_of_bb(v, b)
145143
}
146144

147-
private predicate ssa_defn_rec(LocalScopeVariable v, BasicBlock b) {
145+
private predicate ssa_defn_rec(StackVariable v, BasicBlock b) {
148146
phi_node(v, b)
149147
or
150148
variableUpdate(v, _, b, _)
@@ -155,7 +153,7 @@ library class SSAHelper extends int {
155153
* position `index` in block `b`. This includes definitions from phi nodes.
156154
*/
157155
cached
158-
predicate ssa_defn(LocalScopeVariable v, ControlFlowNode node, BasicBlock b, int index) {
156+
predicate ssa_defn(StackVariable v, ControlFlowNode node, BasicBlock b, int index) {
159157
phi_node(v, b) and b.getStart() = node and index = -1
160158
or
161159
variableUpdate(v, node, b, index)
@@ -179,7 +177,7 @@ library class SSAHelper extends int {
179177
* irrelevant indices at which there is no definition or use when traversing
180178
* basic blocks.
181179
*/
182-
private predicate defUseRank(LocalScopeVariable v, BasicBlock b, int rankix, int i) {
180+
private predicate defUseRank(StackVariable v, BasicBlock b, int rankix, int i) {
183181
i = rank[rankix](int j | ssa_defn(v, _, b, j) or ssa_use(v, _, b, j))
184182
}
185183

@@ -189,15 +187,15 @@ library class SSAHelper extends int {
189187
* the extra rank at the end represents a position past the last node in
190188
* the block.
191189
*/
192-
private int lastRank(LocalScopeVariable v, BasicBlock b) {
190+
private int lastRank(StackVariable v, BasicBlock b) {
193191
result = max(int rankix | defUseRank(v, b, rankix, _)) + 1
194192
}
195193

196194
/**
197195
* Holds if SSA variable `(v, def)` is defined at rank index `rankix` in
198196
* basic block `b`.
199197
*/
200-
private predicate ssaDefRank(LocalScopeVariable v, ControlFlowNode def, BasicBlock b, int rankix) {
198+
private predicate ssaDefRank(StackVariable v, ControlFlowNode def, BasicBlock b, int rankix) {
201199
exists(int i |
202200
ssa_defn(v, def, b, i) and
203201
defUseRank(v, b, rankix, i)
@@ -210,9 +208,7 @@ library class SSAHelper extends int {
210208
* `v` that comes _at or after_ the reached node. Reaching a node means
211209
* that the definition is visible to any _use_ at that node.
212210
*/
213-
private predicate ssaDefReachesRank(
214-
LocalScopeVariable v, ControlFlowNode def, BasicBlock b, int rankix
215-
) {
211+
private predicate ssaDefReachesRank(StackVariable v, ControlFlowNode def, BasicBlock b, int rankix) {
216212
// A definition should not reach its own node unless a loop allows it.
217213
// When nodes are both definitions and uses for the same variable, the
218214
// use is understood to happen _before_ the definition. Phi nodes are
@@ -227,7 +223,7 @@ library class SSAHelper extends int {
227223

228224
/** Holds if SSA variable `(v, def)` reaches the end of block `b`. */
229225
cached
230-
predicate ssaDefinitionReachesEndOfBB(LocalScopeVariable v, ControlFlowNode def, BasicBlock b) {
226+
predicate ssaDefinitionReachesEndOfBB(StackVariable v, ControlFlowNode def, BasicBlock b) {
231227
live_at_exit_of_bb(v, b) and ssaDefReachesRank(v, def, b, lastRank(v, b))
232228
or
233229
exists(BasicBlock idom |
@@ -243,7 +239,7 @@ library class SSAHelper extends int {
243239
* reaches the end of `b`.
244240
*/
245241
pragma[noinline]
246-
private predicate noDefinitionsSinceIDominator(LocalScopeVariable v, BasicBlock idom, BasicBlock b) {
242+
private predicate noDefinitionsSinceIDominator(StackVariable v, BasicBlock idom, BasicBlock b) {
247243
bbIDominates(idom, b) and // It is sufficient to traverse the dominator graph, cf. discussion above.
248244
live_at_exit_of_bb(v, b) and
249245
not ssa_defn(v, _, b, _)
@@ -253,9 +249,7 @@ library class SSAHelper extends int {
253249
* Holds if SSA variable `(v, def)` reaches `use` within the same basic
254250
* block, where `use` is a `VariableAccess` of `v`.
255251
*/
256-
private predicate ssaDefinitionReachesUseWithinBB(
257-
LocalScopeVariable v, ControlFlowNode def, Expr use
258-
) {
252+
private predicate ssaDefinitionReachesUseWithinBB(StackVariable v, ControlFlowNode def, Expr use) {
259253
exists(BasicBlock b, int rankix, int i |
260254
ssaDefReachesRank(v, def, b, rankix) and
261255
defUseRank(v, b, rankix, i) and
@@ -266,7 +260,7 @@ library class SSAHelper extends int {
266260
/**
267261
* Holds if SSA variable `(v, def)` reaches the control-flow node `use`.
268262
*/
269-
private predicate ssaDefinitionReaches(LocalScopeVariable v, ControlFlowNode def, Expr use) {
263+
private predicate ssaDefinitionReaches(StackVariable v, ControlFlowNode def, Expr use) {
270264
ssaDefinitionReachesUseWithinBB(v, def, use)
271265
or
272266
exists(BasicBlock b |
@@ -281,7 +275,7 @@ library class SSAHelper extends int {
281275
* `(node, v)`.
282276
*/
283277
cached
284-
string toString(ControlFlowNode node, LocalScopeVariable v) {
278+
string toString(ControlFlowNode node, StackVariable v) {
285279
if phi_node(v, node.(BasicBlock))
286280
then result = "SSA phi(" + v.getName() + ")"
287281
else (
@@ -294,7 +288,7 @@ library class SSAHelper extends int {
294288
* access of `v`.
295289
*/
296290
cached
297-
VariableAccess getAUse(ControlFlowNode def, LocalScopeVariable v) {
291+
VariableAccess getAUse(ControlFlowNode def, StackVariable v) {
298292
ssaDefinitionReaches(v, def, result) and
299293
ssa_use(v, result, _, _)
300294
}

cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeSSA.qll

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ library class RangeSSA extends SSAHelper {
3131
/**
3232
* Add a phi node on the out-edge of a guard.
3333
*/
34-
override predicate custom_phi_node(LocalScopeVariable v, BasicBlock b) {
34+
override predicate custom_phi_node(StackVariable v, BasicBlock b) {
3535
guard_defn(v.getAnAccess(), _, b, _)
3636
}
3737
}
@@ -67,29 +67,27 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
6767
RangeSsaDefinition() { exists(RangeSSA x | x.ssa_defn(_, this, _, _)) }
6868

6969
/**
70-
* Gets a variable corresponding to a SSA LocalScopeVariable defined by
70+
* Gets a variable corresponding to a SSA StackVariable defined by
7171
* this definition.
7272
*/
73-
LocalScopeVariable getAVariable() { exists(RangeSSA x | x.ssa_defn(result, this, _, _)) }
73+
StackVariable getAVariable() { exists(RangeSSA x | x.ssa_defn(result, this, _, _)) }
7474

7575
/**
7676
* A string representation of the SSA variable represented by the pair
7777
* `(this, v)`.
7878
*/
79-
string toString(LocalScopeVariable v) { exists(RangeSSA x | result = x.toString(this, v)) }
79+
string toString(StackVariable v) { exists(RangeSSA x | result = x.toString(this, v)) }
8080

8181
/** Gets a use of the SSA variable represented by the pair `(this, v)`. */
82-
VariableAccess getAUse(LocalScopeVariable v) { exists(RangeSSA x | result = x.getAUse(this, v)) }
82+
VariableAccess getAUse(StackVariable v) { exists(RangeSSA x | result = x.getAUse(this, v)) }
8383

8484
/** Gets the control flow node for this definition. */
8585
ControlFlowNode getDefinition() { result = this }
8686

8787
BasicBlock getBasicBlock() { result.contains(getDefinition()) }
8888

8989
/** Whether this definition is a phi node for variable `v`. */
90-
predicate isPhiNode(LocalScopeVariable v) {
91-
exists(RangeSSA x | x.phi_node(v, this.(BasicBlock)))
92-
}
90+
predicate isPhiNode(StackVariable v) { exists(RangeSSA x | x.phi_node(v, this.(BasicBlock))) }
9391

9492
/**
9593
* If this definition is a phi node corresponding to a guard,
@@ -104,7 +102,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
104102
/** Whether this definition is from a parameter */
105103
predicate definedByParameter(Parameter p) { this = p.getFunction().getEntryPoint() }
106104

107-
RangeSsaDefinition getAPhiInput(LocalScopeVariable v) {
105+
RangeSsaDefinition getAPhiInput(StackVariable v) {
108106
this.isPhiNode(v) and
109107
exists(BasicBlock pred |
110108
pred = this.(BasicBlock).getAPredecessor() and
@@ -137,7 +135,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
137135
}
138136

139137
/** Gets the expression assigned to this SsaDefinition. */
140-
Expr getDefiningValue(LocalScopeVariable v) {
138+
Expr getDefiningValue(StackVariable v) {
141139
exists(ControlFlowNode def | def = this.getDefinition() |
142140
def = v.getInitializer().getExpr() and def = result
143141
or
@@ -155,7 +153,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
155153
)
156154
}
157155

158-
predicate reachesEndOfBB(LocalScopeVariable v, BasicBlock b) {
156+
predicate reachesEndOfBB(StackVariable v, BasicBlock b) {
159157
exists(RangeSSA x | x.ssaDefinitionReachesEndOfBB(v, this, b))
160158
}
161159
}

cpp/ql/test/library-tests/controlflow/controlflow/SsaCompleteness.ql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ import cpp
99
import semmle.code.cpp.controlflow.SSA
1010

1111
/*
12-
* Count of number of uses of a LocalScopeVariable where no corresponding SSA definition exists,
12+
* Count of number of uses of a StackVariable where no corresponding SSA definition exists,
1313
* but at least one SSA definition for that variable can reach that use.
1414
* Should always be zero *regardless* of the input
1515
*/
1616

17-
select count(LocalScopeVariable v, Expr use |
17+
select count(StackVariable v, Expr use |
1818
exists(SsaDefinition def, BasicBlock db, BasicBlock ub |
1919
def.getAUse(v) = use and db.contains(def.getDefinition()) and ub.contains(use)
2020
|

0 commit comments

Comments
 (0)