Skip to content

Commit 54edfc5

Browse files
committed
Base SSA classes on shared SSA library
1 parent 5bc4ccf commit 54edfc5

File tree

2 files changed

+32
-140
lines changed

2 files changed

+32
-140
lines changed

go/ql/lib/semmle/go/dataflow/SSA.qll

+24-55
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ private predicate unresolvedIdentifier(Ident id, string name) {
6161
/**
6262
* An SSA variable.
6363
*/
64-
class SsaVariable extends TSsaDefinition {
64+
class SsaVariable instanceof SsaDefinition {
6565
/** Gets the source variable corresponding to this SSA variable. */
6666
SsaSourceVariable getSourceVariable() { result = this.(SsaDefinition).getSourceVariable() }
6767

@@ -107,27 +107,26 @@ class SsaVariable extends TSsaDefinition {
107107
/**
108108
* An SSA definition.
109109
*/
110-
class SsaDefinition extends TSsaDefinition {
110+
class SsaDefinition instanceof ZZZDefinition {
111+
/**
112+
* Holds if this SSA definition defines `v` at index `i` in basic block `bb`.
113+
* Phi nodes are considered to be at index `-1`, while normal variable writes
114+
* are at the index of the control flow node they wrap.
115+
*/
116+
predicate definesAt(SsaSourceVariable v, BasicBlock bb, int i) {
117+
this.(ZZZDefinition).definesAt(v, bb, i)
118+
}
119+
111120
/** Gets the SSA variable defined by this definition. */
112121
SsaVariable getVariable() { result = this }
113122

114123
/** Gets the source variable defined by this definition. */
115-
abstract SsaSourceVariable getSourceVariable();
124+
SsaSourceVariable getSourceVariable() { this.definesAt(result, _, _) }
116125

117126
/**
118127
* Gets the basic block to which this definition belongs.
119128
*/
120-
abstract ReachableBasicBlock getBasicBlock();
121-
122-
/**
123-
* INTERNAL: Use `getBasicBlock()` and `getSourceVariable()` instead.
124-
*
125-
* Holds if this is a definition of source variable `v` at index `idx` in basic block `bb`.
126-
*
127-
* Phi nodes are considered to be at index `-1`, all other definitions at the index of
128-
* the control flow node they correspond to.
129-
*/
130-
abstract predicate definesAt(SsaSourceVariable v, ReachableBasicBlock bb, int idx);
129+
ReachableBasicBlock getBasicBlock() { this.definesAt(_, result, _) }
131130

132131
/**
133132
* INTERNAL: Use `toString()` instead.
@@ -146,12 +145,12 @@ class SsaDefinition extends TSsaDefinition {
146145
/** Gets the innermost function or file to which this SSA definition belongs. */
147146
ControlFlow::Root getRoot() { result = this.getBasicBlock().getRoot() }
148147

148+
/** Gets the location of this SSA definition. */
149+
Location getLocation() { result = this.(ZZZDefinition).getLocation() }
150+
149151
/** Gets a textual representation of this element. */
150152
string toString() { result = this.prettyPrintDef() }
151153

152-
/** Gets the source location for this element. */
153-
abstract Location getLocation();
154-
155154
/**
156155
* DEPRECATED: Use `getLocation()` instead.
157156
*
@@ -178,32 +177,22 @@ class SsaDefinition extends TSsaDefinition {
178177
/**
179178
* An SSA definition that corresponds to an explicit assignment or other variable definition.
180179
*/
181-
class SsaExplicitDefinition extends SsaDefinition, TExplicitDef {
180+
class SsaExplicitDefinition extends SsaDefinition {
182181
/** Gets the instruction where the definition happens. */
183182
IR::Instruction getInstruction() {
184-
exists(BasicBlock bb, int i | this = TExplicitDef(bb, i, _) | result = bb.getNode(i))
183+
exists(BasicBlock bb, int i | this.definesAt(_, bb, i) | result = bb.getNode(i))
185184
}
186185

187186
/** Gets the right-hand side of the definition. */
188187
IR::Instruction getRhs() { this.getInstruction().writes(_, result) }
189188

190-
override predicate definesAt(SsaSourceVariable v, ReachableBasicBlock bb, int i) {
191-
this = TExplicitDef(bb, i, v)
192-
}
193-
194-
override ReachableBasicBlock getBasicBlock() { this.definesAt(_, result, _) }
195-
196-
override SsaSourceVariable getSourceVariable() { this.definesAt(result, _, _) }
197-
198189
override string prettyPrintRef() {
199190
exists(Location loc | loc = this.getLocation() |
200191
result = "def@" + loc.getStartLine() + ":" + loc.getStartColumn()
201192
)
202193
}
203194

204195
override string prettyPrintDef() { result = "definition of " + this.getSourceVariable() }
205-
206-
override Location getLocation() { result = this.getInstruction().getLocation() }
207196
}
208197

209198
/** Provides a helper predicate for working with explicit SSA definitions. */
@@ -230,8 +219,6 @@ abstract class SsaImplicitDefinition extends SsaDefinition {
230219
result = this.getKind() + "@" + loc.getStartLine() + ":" + loc.getStartColumn()
231220
)
232221
}
233-
234-
override Location getLocation() { result = this.getBasicBlock().getLocation() }
235222
}
236223

237224
/**
@@ -241,24 +228,16 @@ abstract class SsaImplicitDefinition extends SsaDefinition {
241228
* Capturing definitions appear at the beginning of such functions, as well as
242229
* at any function call that may affect the value of the variable.
243230
*/
244-
class SsaVariableCapture extends SsaImplicitDefinition, TCapture {
245-
override predicate definesAt(SsaSourceVariable v, ReachableBasicBlock bb, int i) {
246-
this = TCapture(bb, i, v)
231+
class SsaVariableCapture extends SsaImplicitDefinition {
232+
SsaVariableCapture() {
233+
exists(BasicBlock bb, int i, SsaSourceVariable v | this.definesAt(v, bb, i) |
234+
mayCapture(bb, i, v)
235+
)
247236
}
248237

249-
override ReachableBasicBlock getBasicBlock() { this.definesAt(_, result, _) }
250-
251-
override SsaSourceVariable getSourceVariable() { this.definesAt(result, _, _) }
252-
253238
override string getKind() { result = "capture" }
254239

255240
override string prettyPrintDef() { result = "capture variable " + this.getSourceVariable() }
256-
257-
override Location getLocation() {
258-
exists(ReachableBasicBlock bb, int i | this.definesAt(_, bb, i) |
259-
result = bb.getNode(i).getLocation()
260-
)
261-
}
262241
}
263242

264243
/**
@@ -283,26 +262,16 @@ abstract class SsaPseudoDefinition extends SsaImplicitDefinition {
283262
* in the flow graph where otherwise two or more definitions for the variable
284263
* would be visible.
285264
*/
286-
class SsaPhiNode extends SsaPseudoDefinition, TPhi {
265+
class SsaPhiNode extends SsaPseudoDefinition instanceof ZZZPhiNode {
287266
override SsaVariable getAnInput() {
288267
result = getDefReachingEndOf(this.getBasicBlock().getAPredecessor(), this.getSourceVariable())
289268
}
290269

291-
override predicate definesAt(SsaSourceVariable v, ReachableBasicBlock bb, int i) {
292-
bb = this.getBasicBlock() and v = this.getSourceVariable() and i = -1
293-
}
294-
295-
override ReachableBasicBlock getBasicBlock() { this = TPhi(result, _) }
296-
297-
override SsaSourceVariable getSourceVariable() { this = TPhi(_, result) }
298-
299270
override string getKind() { result = "phi" }
300271

301272
override string prettyPrintDef() {
302273
result = this.getSourceVariable() + " = phi(" + this.ppInputs() + ")"
303274
}
304-
305-
override Location getLocation() { result = this.getBasicBlock().getLocation() }
306275
}
307276

308277
/**

go/ql/lib/semmle/go/dataflow/SsaImpl.qll

+8-85
Original file line numberDiff line numberDiff line change
@@ -21,61 +21,6 @@ private module Internal {
2121
bb.getNode(i).(IR::Instruction).reads(v)
2222
}
2323

24-
/**
25-
* A data type representing SSA definitions.
26-
*
27-
* We distinguish three kinds of SSA definitions:
28-
*
29-
* 1. Variable definitions, including declarations, assignments and increments/decrements.
30-
* 2. Pseudo-definitions for captured variables at the beginning of the capturing function
31-
* as well as after calls.
32-
* 3. Phi nodes.
33-
*
34-
* SSA definitions are only introduced where necessary. In particular,
35-
* unreachable code has no SSA definitions associated with it, and neither
36-
* have dead assignments (that is, assignments whose value is never read).
37-
*/
38-
cached
39-
newtype TSsaDefinition =
40-
/**
41-
* An SSA definition that corresponds to an explicit assignment or other variable definition.
42-
*/
43-
TExplicitDef(ReachableBasicBlock bb, int i, SsaSourceVariable v) {
44-
defAt(bb, i, v) and
45-
(liveAfterDef(bb, i, v) or v.isCaptured())
46-
} or
47-
/**
48-
* An SSA definition representing the capturing of an SSA-convertible variable
49-
* in the closure of a nested function.
50-
*
51-
* Capturing definitions appear at the beginning of such functions, as well as
52-
* at any function call that may affect the value of the variable.
53-
*/
54-
TCapture(ReachableBasicBlock bb, int i, SsaSourceVariable v) {
55-
mayCapture(bb, i, v) and
56-
liveAfterDef(bb, i, v)
57-
} or
58-
/**
59-
* An SSA phi node, that is, a pseudo-definition for a variable at a point
60-
* in the flow graph where otherwise two or more definitions for the variable
61-
* would be visible.
62-
*/
63-
TPhi(ReachableJoinBlock bb, SsaSourceVariable v) {
64-
liveAtEntry(bb, v) and
65-
inDefDominanceFrontier(bb, v)
66-
}
67-
68-
/**
69-
* Holds if `bb` is in the dominance frontier of a block containing a definition of `v`.
70-
*/
71-
pragma[noinline]
72-
private predicate inDefDominanceFrontier(ReachableJoinBlock bb, SsaSourceVariable v) {
73-
exists(ReachableBasicBlock defbb, SsaDefinition def |
74-
def.definesAt(v, defbb, _) and
75-
bb.inDominanceFrontierOf(defbb)
76-
)
77-
}
78-
7924
/**
8025
* Holds if `v` is a captured variable which is declared in `declFun` and read in `useFun`.
8126
*/
@@ -104,7 +49,8 @@ private module Internal {
10449
* modeling updates to captured variable `v`. Whether the definition is actually
10550
* introduced depends on whether `v` is live at this point in the program.
10651
*/
107-
private predicate mayCapture(ReachableBasicBlock bb, int i, SsaSourceVariable v) {
52+
cached
53+
predicate mayCapture(ReachableBasicBlock bb, int i, SsaSourceVariable v) {
10854
exists(FuncDef capturingContainer, FuncDef declContainer |
10955
// capture initial value of variable declared in enclosing scope
11056
readsCapturedVar(capturingContainer, v, declContainer) and
@@ -143,31 +89,6 @@ private module Internal {
14389
ref(bb, i, v, tp)
14490
}
14591

146-
/**
147-
* Gets the maximum rank among all references to `v` in basic block `bb`.
148-
*/
149-
private int maxRefRank(ReachableBasicBlock bb, SsaSourceVariable v) {
150-
result = max(refRank(bb, _, v, _))
151-
}
152-
153-
/**
154-
* Holds if variable `v` is live after the `i`th node of basic block `bb`, where
155-
* `i` is the index of a node that may assign or capture `v`.
156-
*
157-
* For the purposes of this predicate, function calls are considered as writes of captured variables.
158-
*/
159-
private predicate liveAfterDef(ReachableBasicBlock bb, int i, SsaSourceVariable v) {
160-
exists(int r | r = refRank(bb, i, v, WriteRef()) |
161-
// the next reference to `v` inside `bb` is a read
162-
r + 1 = refRank(bb, _, v, ReadRef())
163-
or
164-
// this is the last reference to `v` inside `bb`, but `v` is live at entry
165-
// to a successor basic block of `bb`
166-
r = maxRefRank(bb, v) and
167-
liveAtSuccEntry(bb, v)
168-
)
169-
}
170-
17192
/**
17293
* Holds if variable `v` is live at the beginning of basic block `bb`.
17394
*
@@ -502,13 +423,15 @@ private module Internal {
502423

503424
import SsaImplCommon::Make<Location, SsaInput> as Impl
504425

505-
final class SsaInputDefinition = Impl::Definition;
426+
final class ZZZDefinition = Impl::Definition;
506427

507-
final class SsaInputWriteDefinition = Impl::WriteDefinition;
428+
final class ZZZWriteDefinition = Impl::WriteDefinition;
508429

509-
final class SsaInputUncertainWriteDefinition = Impl::UncertainWriteDefinition;
430+
final class ZZZUncertainWriteDefinition = Impl::UncertainWriteDefinition;
510431

511-
final class SsaInputPhiNode = Impl::PhiNode;
432+
final class ZZZPhiNode = Impl::PhiNode;
512433
}
513434

514435
import Internal
436+
437+
predicate captures = Internal::mayCapture/3;

0 commit comments

Comments
 (0)