Skip to content

Commit deecb41

Browse files
committed
Squash this later
1 parent 4b95ea0 commit deecb41

File tree

3 files changed

+264
-1
lines changed

3 files changed

+264
-1
lines changed

go/ql/lib/go.qll

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ import semmle.go.frameworks.Afero
3232
import semmle.go.frameworks.AwsLambda
3333
import semmle.go.frameworks.Beego
3434
import semmle.go.frameworks.BeegoOrm
35-
import semmle.go.frameworks.Chi
3635
import semmle.go.frameworks.RsCors
3736
import semmle.go.frameworks.Couchbase
3837
import semmle.go.frameworks.Echo

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

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,37 @@ class SsaSourceVariable extends LocalVariable {
3737
}
3838
}
3939

40+
/**
41+
* A variable that can be SSA converted, that is, a global variable
42+
*/
43+
class SsaGlobalSourceVariable extends DeclaredVariable {
44+
SsaGlobalSourceVariable() { not this.getScope() instanceof LocalScope }
45+
46+
/**
47+
* Holds if there may be indirect references of this variable that are not covered by `getAReference()`.
48+
*
49+
* This is the case for variables that have their address taken, and for variables whose
50+
* name resolution information may be incomplete (for instance due to an extractor error).
51+
*/
52+
predicate mayHaveIndirectReferences() {
53+
// variables that have their address taken
54+
exists(AddressExpr addr | addr.getOperand().stripParens() = this.getAReference())
55+
or
56+
exists(DataFlow::MethodReadNode mrn |
57+
mrn.getReceiver() = this.getARead() and
58+
mrn.getMethod().getReceiverType() instanceof PointerType
59+
)
60+
or
61+
// variables where there is an unresolved reference with the same name in the same
62+
// scope or a nested scope, suggesting that name resolution information may be incomplete
63+
exists(FunctionScope scope, FuncDef inner |
64+
scope = this.getScope().(LocalScope).getEnclosingFunctionScope() and
65+
unresolvedReference(this.getName(), inner) and
66+
inner.getScope().getOuterScope*() = scope
67+
)
68+
}
69+
}
70+
4071
/**
4172
* Holds if there is an unresolved reference to `name` in `fn`.
4273
*/
@@ -99,6 +130,48 @@ class SsaVariable extends TSsaDefinition {
99130
}
100131
}
101132

133+
134+
/**
135+
* A global SSA variable.
136+
*/
137+
class SsaGlobalVariable extends TGlobalSsaDefinition {
138+
/** Gets the source variable corresponding to this SSA variable. */
139+
SsaGlobalSourceVariable getSourceVariable() { result = this.(SsaGlobalDefinition).getSourceVariable() }
140+
141+
/** Gets the (unique) definition of this SSA variable. */
142+
SsaGlobalDefinition getDefinition() { result = this }
143+
144+
/** Gets the type of this SSA variable. */
145+
Type getType() { result = this.getSourceVariable().getType() }
146+
147+
/** Gets a use in basic block `bb` that refers to this SSA variable. */
148+
IR::Instruction getAUseIn(ReachableBasicBlock bb) {
149+
exists(int i, SsaGlobalSourceVariable v | v = this.getSourceVariable() |
150+
result = bb.getNode(i) and
151+
this = getGlobalDefinition(bb, i, v)
152+
)
153+
}
154+
155+
/** Gets a use that refers to this SSA variable. */
156+
IR::Instruction getAUse() { result = this.getAUseIn(_) }
157+
158+
/** Gets a textual representation of this element. */
159+
string toString() { result = this.getDefinition().prettyPrintRef() }
160+
161+
/**
162+
* Holds if this element is at the specified location.
163+
* The location spans column `startcolumn` of line `startline` to
164+
* column `endcolumn` of line `endline` in file `filepath`.
165+
* For more information, see
166+
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
167+
*/
168+
predicate hasLocationInfo(
169+
string filepath, int startline, int startcolumn, int endline, int endcolumn
170+
) {
171+
this.getDefinition().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
172+
}
173+
}
174+
102175
/**
103176
* An SSA definition.
104177
*/
@@ -156,6 +229,63 @@ class SsaDefinition extends TSsaDefinition {
156229
);
157230
}
158231

232+
/**
233+
* A global SSA definition.
234+
*/
235+
class SsaGlobalDefinition extends TGlobalSsaDefinition {
236+
/** Gets the SSA variable defined by this definition. */
237+
SsaGlobalVariable getVariable() { result = this }
238+
239+
/** Gets the source variable defined by this definition. */
240+
abstract SsaGlobalSourceVariable getSourceVariable();
241+
242+
/**
243+
* Gets the basic block to which this definition belongs.
244+
*/
245+
abstract ReachableBasicBlock getBasicBlock();
246+
247+
/**
248+
* INTERNAL: Use `getBasicBlock()` and `getSourceVariable()` instead.
249+
*
250+
* Holds if this is a definition of source variable `v` at index `idx` in basic block `bb`.
251+
*
252+
* Phi nodes are considered to be at index `-1`, all other definitions at the index of
253+
* the control flow node they correspond to.
254+
*/
255+
abstract predicate definesAt(ReachableBasicBlock bb, int idx, SsaSourceVariable v);
256+
257+
/**
258+
* INTERNAL: Use `toString()` instead.
259+
*
260+
* Gets a pretty-printed representation of this SSA definition.
261+
*/
262+
abstract string prettyPrintDef();
263+
264+
/**
265+
* INTERNAL: Do not use.
266+
*
267+
* Gets a pretty-printed representation of a reference to this SSA definition.
268+
*/
269+
abstract string prettyPrintRef();
270+
271+
/** Gets the innermost function or file to which this SSA definition belongs. */
272+
ControlFlow::Root getRoot() { result = this.getBasicBlock().getRoot() }
273+
274+
/** Gets a textual representation of this element. */
275+
string toString() { result = this.prettyPrintDef() }
276+
277+
/**
278+
* Holds if this element is at the specified location.
279+
* The location spans column `startcolumn` of line `startline` to
280+
* column `endcolumn` of line `endline` in file `filepath`.
281+
* For more information, see
282+
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
283+
*/
284+
abstract predicate hasLocationInfo(
285+
string filepath, int startline, int startcolumn, int endline, int endcolumn
286+
);
287+
}
288+
159289
/**
160290
* An SSA definition that corresponds to an explicit assignment or other variable definition.
161291
*/
@@ -302,6 +432,14 @@ class SsaPhiNode extends SsaPseudoDefinition, TPhi {
302432
}
303433
}
304434

435+
436+
/**
437+
* An SSA variable, possibly with a chain of field reads on it.
438+
*/
439+
private newtype TGlobalSsaWithFields =
440+
TGlobalRoot(SsaGlobalVariable v) or
441+
TGlobalStep(GlobalWithFields base, Field f) { exists(accessPathAux(base, f)) }
442+
305443
/**
306444
* An SSA variable, possibly with a chain of field reads on it.
307445
*/
@@ -401,6 +539,75 @@ class SsaWithFields extends TSsaWithFields {
401539
}
402540
}
403541

542+
543+
/** An SSA variable with zero or more fields read from it. */
544+
class GlobalWithFields extends TSsaWithFields {
545+
/**
546+
* Gets the SSA variable corresponding to the base of this SSA variable with fields.
547+
*
548+
* For example, the SSA variable corresponding to `a` for the SSA variable with fields
549+
* corresponding to `a.b`.
550+
*/
551+
SsaVariable getBaseVariable() {
552+
this = TRoot(result)
553+
or
554+
exists(GlobalWithFields base | this = TStep(base, _) | result = base.getBaseVariable())
555+
}
556+
557+
/** Gets a use that refers to this SSA variable with fields. */
558+
DataFlow::Node getAUse() { this = accessPath(result.asInstruction()) }
559+
560+
/** Gets the type of this SSA variable with fields. */
561+
Type getType() {
562+
exists(SsaVariable var | this = TRoot(var) | result = var.getType())
563+
or
564+
exists(Field f | this = TStep(_, f) | result = f.getType())
565+
}
566+
567+
/** Gets a textual representation of this element. */
568+
string toString() {
569+
exists(SsaVariable var | this = TRoot(var) | result = "(" + var + ")")
570+
or
571+
exists(GlobalWithFields base, Field f | this = TStep(base, f) | result = base + "." + f.getName())
572+
}
573+
574+
/**
575+
* Gets an SSA-with-fields variable that is similar to this SSA-with-fields variable in the
576+
* sense that it has the same root variable and the same sequence of field accesses.
577+
*/
578+
GlobalWithFields similar() {
579+
result.getBaseVariable().getSourceVariable() = this.getBaseVariable().getSourceVariable() and
580+
result.getQualifiedName() = this.getQualifiedName()
581+
}
582+
583+
/**
584+
* Gets the qualified name of the source variable or variable and fields that this represents.
585+
*
586+
* For example, for an SSA variable that represents the field `a.b`, this would get the string
587+
* `"a.b"`.
588+
*/
589+
string getQualifiedName() {
590+
exists(SsaVariable v | this = TRoot(v) and result = v.getSourceVariable().getName())
591+
or
592+
exists(GlobalWithFields base, Field f | this = TStep(base, f) |
593+
result = base.getQualifiedName() + "." + f.getName()
594+
)
595+
}
596+
597+
/**
598+
* Holds if this element is at the specified location.
599+
* The location spans column `startcolumn` of line `startline` to
600+
* column `endcolumn` of line `endline` in file `filepath`.
601+
* For more information, see
602+
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
603+
*/
604+
predicate hasLocationInfo(
605+
string filepath, int startline, int startcolumn, int endline, int endcolumn
606+
) {
607+
this.getBaseVariable().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
608+
}
609+
}
610+
404611
/**
405612
* Gets a read similar to `node`, according to the same rules as `SsaWithFields.similar()`.
406613
*/

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

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,52 @@ private module Internal {
7575
)
7676
}
7777

78+
79+
80+
/**
81+
* A data type representing SSA definitions.
82+
*
83+
* We distinguish three kinds of SSA definitions:
84+
*
85+
* 1. Variable definitions, including declarations, assignments and increments/decrements.
86+
* 2. Pseudo-definitions for captured variables at the beginning of the capturing function
87+
* as well as after calls.
88+
* 3. Phi nodes.
89+
*
90+
* SSA definitions are only introduced where necessary. In particular,
91+
* unreachable code has no SSA definitions associated with it, and neither
92+
* have dead assignments (that is, assignments whose value is never read).
93+
*/
94+
cached
95+
newtype TGlobalSsaDefinition =
96+
/**
97+
* An SSA definition that corresponds to an explicit assignment or other variable definition.
98+
*/
99+
TGlobalExplicitDef(ReachableBasicBlock bb, int i, SsaGlobalSourceVariable v) {
100+
defAt(bb, i, v)
101+
102+
} or
103+
/**
104+
* An SSA definition representing the capturing of an SSA-convertible variable
105+
* in the closure of a nested function.
106+
*
107+
* Capturing definitions appear at the beginning of such functions, as well as
108+
* at any function call that may affect the value of the variable.
109+
*/
110+
TGlobalCapture(ReachableBasicBlock bb, int i, SsaGlobalSourceVariable v) {
111+
mayCapture(bb, i, v)
112+
} or
113+
/**
114+
* An SSA phi node, that is, a pseudo-definition for a variable at a point
115+
* in the flow graph where otherwise two or more definitions for the variable
116+
* would be visible.
117+
*/
118+
TGlbalPhi(ReachableJoinBlock bb, SsaGlobalSourceVariable v) {
119+
liveAtEntry(bb, v) and
120+
inDefDominanceFrontier(bb, v)
121+
}
122+
123+
78124
/**
79125
* Holds if `v` is a captured variable which is declared in `declFun` and read in `useFun`.
80126
*/
@@ -290,6 +336,17 @@ private module Internal {
290336
or
291337
rewindReads(bb, i, v) = 1 and result = getDefReachingEndOf(bb.getImmediateDominator(), v)
292338
}
339+
340+
/**
341+
* Gets the unique SSA definition of `v` whose value reaches the `i`th node of `bb`,
342+
* which is a use of `v`.
343+
*/
344+
cached
345+
SsaGlobalDefinition getGlobalDefinition(ReachableBasicBlock bb, int i, SsaSourceVariable v) {
346+
result = getLocalDefinition(bb, i, v)
347+
or
348+
rewindReads(bb, i, v) = 1 and result = getDefReachingEndOf(bb.getImmediateDominator(), v)
349+
}
293350
}
294351

295352
import Internal

0 commit comments

Comments
 (0)