Skip to content

Commit 5c3ff8a

Browse files
authored
Merge pull request #604 from markshannon/python-faster-essa-computation
Python : Speed up ESSA computation
2 parents 732874b + 68440f7 commit 5c3ff8a

File tree

4 files changed

+106
-47
lines changed

4 files changed

+106
-47
lines changed

python/ql/src/semmle/dataflow/SSA.qll

Lines changed: 67 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ private string location_string(EssaVariable v) {
154154
|
155155
def = TEssaNodeDefinition(_, b, index)
156156
or
157+
def = TEssaNodeRefinement(_, b, index)
158+
or
157159
def = TEssaEdgeDefinition(_, _, b) and index = piIndex()
158160
or
159161
def = TPhiFunction(_, b) and index = phiIndex()
@@ -177,7 +179,11 @@ private int var_rank(EssaVariable v) {
177179
/** Underlying IPA type for EssaDefinition and EssaVariable. */
178180
private cached newtype TEssaDefinition =
179181
TEssaNodeDefinition(SsaSourceVariable v, BasicBlock b, int i) {
180-
EssaDefinitions::variableUpdate(v, _, b, _, i)
182+
EssaDefinitions::variableDefinition(v, _, b, _, i)
183+
}
184+
or
185+
TEssaNodeRefinement(SsaSourceVariable v, BasicBlock b, int i) {
186+
EssaDefinitions::variableRefinement(v, _, b, _, i)
181187
}
182188
or
183189
TEssaEdgeDefinition(SsaSourceVariable v, BasicBlock pred, BasicBlock succ) {
@@ -446,21 +452,15 @@ class PhiFunction extends EssaDefinition, TPhiFunction {
446452
}
447453
}
448454

449-
library class EssaNode extends EssaDefinition, TEssaNodeDefinition {
455+
/** A definition of an ESSA variable that is not directly linked to
456+
* another ESSA variable.
457+
*/
458+
class EssaNodeDefinition extends EssaDefinition, TEssaNodeDefinition {
450459

451460
override string toString() {
452461
result = "Essa node definition"
453462
}
454463

455-
/** Gets the ControlFlowNode corresponding to this definition */
456-
ControlFlowNode getDefiningNode() {
457-
this.definedBy(_, result)
458-
}
459-
460-
override Location getLocation() {
461-
result = this.getDefiningNode().getLocation()
462-
}
463-
464464
override ControlFlowNode getAUse() {
465465
exists(SsaSourceVariable v, BasicBlock b, int i |
466466
this = TEssaNodeDefinition(v, b, i) and
@@ -479,6 +479,15 @@ library class EssaNode extends EssaDefinition, TEssaNodeDefinition {
479479
this = TEssaNodeDefinition(result, _, _)
480480
}
481481

482+
/** Gets the ControlFlowNode corresponding to this definition */
483+
ControlFlowNode getDefiningNode() {
484+
this.definedBy(_, result)
485+
}
486+
487+
override Location getLocation() {
488+
result = this.getDefiningNode().getLocation()
489+
}
490+
482491
override string getRepresentation() {
483492
result = this.getDefiningNode().toString()
484493
}
@@ -501,27 +510,9 @@ library class EssaNode extends EssaDefinition, TEssaNodeDefinition {
501510

502511
}
503512

504-
/** A definition of an ESSA variable that is not directly linked to
505-
* another ESSA variable.
506-
*/
507-
class EssaNodeDefinition extends EssaNode {
508-
509-
EssaNodeDefinition() {
510-
this.getSourceVariable().hasDefiningNode(this.getDefiningNode())
511-
}
512-
513-
}
514-
515513
/** A definition of an ESSA variable that takes another ESSA variable as an input.
516514
*/
517-
class EssaNodeRefinement extends EssaNode {
518-
519-
EssaNodeRefinement() {
520-
exists(SsaSourceVariable v, ControlFlowNode def |
521-
this.definedBy(v, def) and
522-
v.hasRefinement(_, def)
523-
)
524-
}
515+
class EssaNodeRefinement extends EssaDefinition, TEssaNodeRefinement {
525516

526517
override string toString() {
527518
result = "SSA filter definition"
@@ -533,22 +524,62 @@ class EssaNodeRefinement extends EssaNode {
533524
not result = potential_input(potential_input(this).getDefinition())
534525
}
535526

527+
override ControlFlowNode getAUse() {
528+
exists(SsaSourceVariable v, BasicBlock b, int i |
529+
this = TEssaNodeRefinement(v, b, i) and
530+
SsaDefinitions::reachesUse(v, b, i, result)
531+
)
532+
}
533+
534+
override predicate reachesEndOfBlock(BasicBlock b) {
535+
exists(BasicBlock defb, int i |
536+
this = TEssaNodeRefinement(_, defb, i) and
537+
SsaDefinitions::reachesEndOfBlock(this.getSourceVariable(), defb, i, b)
538+
)
539+
}
540+
541+
override SsaSourceVariable getSourceVariable() {
542+
this = TEssaNodeRefinement(result, _, _)
543+
}
544+
545+
/** Gets the ControlFlowNode corresponding to this definition */
546+
ControlFlowNode getDefiningNode() {
547+
this.definedBy(_, result)
548+
}
549+
550+
override Location getLocation() {
551+
result = this.getDefiningNode().getLocation()
552+
}
553+
536554
override string getRepresentation() {
537555
result = this.getAQlClass() + "(" + this.getInput().getRepresentation() + ")"
538556
}
539557

558+
override Scope getScope() {
559+
exists(BasicBlock defb |
560+
this = TEssaNodeRefinement(_, defb, _) and
561+
result = defb.getScope()
562+
)
563+
}
564+
565+
predicate definedBy(SsaSourceVariable v, ControlFlowNode def) {
566+
exists(BasicBlock b, int i |
567+
def = b.getNode(i) |
568+
this = TEssaNodeRefinement(v, b, i+i)
569+
or
570+
this = TEssaNodeRefinement(v, b, i+i+1)
571+
)
572+
}
573+
540574
}
541575

542576
pragma[noopt]
543577
private EssaVariable potential_input(EssaNodeRefinement ref) {
544-
exists(EssaNode node, ControlFlowNode use, SsaSourceVariable var, ControlFlowNode def |
578+
exists(ControlFlowNode use, SsaSourceVariable var, ControlFlowNode def |
545579
var.hasRefinement(use, def) and
546580
use = result.getAUse() and
547581
var = result.getSourceVariable() and
548-
def = node.getDefiningNode() and
549-
var = node.getSourceVariable() and
550-
ref = (EssaNodeRefinement)node
582+
def = ref.getDefiningNode() and
583+
var = ref.getSourceVariable()
551584
)
552585
}
553-
554-

python/ql/src/semmle/dataflow/SsaCompute.qll

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,19 @@ private cached module SsaComputeImpl {
9999
cached module EssaDefinitionsImpl {
100100

101101
/** Whether `n` is a live update that is a definition of the variable `v`. */
102-
cached predicate variableUpdate(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int rankix, int i) {
103-
SsaComputeImpl::variableDef(v, n, b, i) and
102+
cached predicate variableDefinition(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int rankix, int i) {
103+
SsaComputeImpl::variableDefine(v, n, b, i) and
104+
SsaComputeImpl::defUseRank(v, b, rankix, i) and
105+
(
106+
SsaComputeImpl::defUseRank(v, b, rankix+1, _) and not SsaComputeImpl::defRank(v, b, rankix+1, _)
107+
or
108+
not SsaComputeImpl::defUseRank(v, b, rankix+1, _) and Liveness::liveAtExit(v, b)
109+
)
110+
}
111+
112+
/** Whether `n` is a live update that is a definition of the variable `v`. */
113+
cached predicate variableRefinement(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int rankix, int i) {
114+
SsaComputeImpl::variableRefine(v, n, b, i) and
104115
SsaComputeImpl::defUseRank(v, b, rankix, i) and
105116
(
106117
SsaComputeImpl::defUseRank(v, b, rankix+1, _) and not SsaComputeImpl::defRank(v, b, rankix+1, _)
@@ -109,6 +120,12 @@ private cached module SsaComputeImpl {
109120
)
110121
}
111122

123+
cached predicate variableUpdate(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int rankix, int i) {
124+
variableDefinition(v, n, b, rankix, i)
125+
or
126+
variableRefinement(v, n, b, rankix, i)
127+
}
128+
112129
/** Holds if `def` is a pi-node for `v` on the edge `pred` -> `succ` */
113130
cached predicate piNode(SsaSourceVariable v, BasicBlock pred, BasicBlock succ) {
114131
v.hasRefinementEdge(_, pred, succ) and
@@ -128,15 +145,28 @@ private cached module SsaComputeImpl {
128145
}
129146
}
130147

131-
cached predicate variableDef(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) {
132-
(v.hasDefiningNode(n) or v.hasRefinement(_, n))
148+
cached predicate variableDefine(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) {
149+
v.hasDefiningNode(n)
150+
and
151+
exists(int j |
152+
n = b.getNode(j) and
153+
i = j*2 + 1
154+
)
155+
}
156+
157+
cached predicate variableRefine(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) {
158+
v.hasRefinement(_, n)
133159
and
134160
exists(int j |
135-
n = b.getNode(j) and
161+
n = b.getNode(j) and
136162
i = j*2 + 1
137163
)
138164
}
139165

166+
cached predicate variableDef(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) {
167+
variableDefine(v, n, b, i) or variableRefine(v, n, b, i)
168+
}
169+
140170
/**
141171
* A ranking of the indices `i` at which there is an SSA definition or use of
142172
* `v` in the basic block `b`.

python/ql/src/semmle/python/pointsto/Base.qll

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,6 @@ predicate function_can_never_return(FunctionObject func) {
202202
/** Python specific sub-class of generic EssaNodeDefinition */
203203
class PyNodeDefinition extends EssaNodeDefinition {
204204

205-
PyNodeDefinition() {
206-
this.getSourceVariable().hasDefiningNode(this.getDefiningNode())
207-
}
208-
209205
override string getRepresentation() {
210206
result = this.getAQlClass()
211207
}

python/ql/src/semmle/python/security/TaintTracking.qll

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ abstract class TaintSource extends @py_flow_node {
416416
* Users of the taint tracking library can override this
417417
* class to provide their own sources on the ESSA graph.
418418
*/
419-
abstract class TaintedDefinition extends EssaNode {
419+
abstract class TaintedDefinition extends EssaNodeDefinition {
420420

421421
/**
422422
* Holds if `this` is a source of taint kind `kind`
@@ -1067,7 +1067,9 @@ library module TaintFlowImplementation {
10671067
not exists(Sanitizer san |
10681068
san.sanitizingDefinition(kind, def)
10691069
or
1070-
san.sanitizingNode(kind, def.(EssaNode).getDefiningNode())
1070+
san.sanitizingNode(kind, def.(EssaNodeDefinition).getDefiningNode())
1071+
or
1072+
san.sanitizingNode(kind, def.(EssaNodeRefinement).getDefiningNode())
10711073
)
10721074
)
10731075
)

0 commit comments

Comments
 (0)