Skip to content

Commit b9a5b3b

Browse files
committed
Python: Remove points-to from SSA.ql
Happily, this was not as deeply entwined as it looked at first glance.
1 parent 5b47fcb commit b9a5b3b

File tree

2 files changed

+89
-85
lines changed

2 files changed

+89
-85
lines changed

python/ql/lib/LegacyPointsTo.qll

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,3 +340,91 @@ Object getLiteralObject(ImmutableLiteral l) {
340340
name_consts(l, "None") and
341341
result = theNoneObject()
342342
}
343+
344+
private predicate gettext_installed() {
345+
// Good enough (and fast) approximation
346+
exists(Module m | m.getName() = "gettext")
347+
}
348+
349+
private predicate builtin_constant(string name) {
350+
exists(Object::builtin(name))
351+
or
352+
name = "WindowsError"
353+
or
354+
name = "_" and gettext_installed()
355+
}
356+
357+
/** Whether this name is (almost) always defined, ie. it is a builtin or VM defined name */
358+
predicate globallyDefinedName(string name) { builtin_constant(name) or auto_name(name) }
359+
360+
private predicate auto_name(string name) {
361+
name = "__file__" or name = "__builtins__" or name = "__name__"
362+
}
363+
364+
/** An extension of `SsaVariable` that provides points-to related methods. */
365+
class SsaVariableWithPointsTo extends SsaVariable {
366+
/** Gets an argument of the phi function defining this variable, pruned of unlikely edges. */
367+
SsaVariable getAPrunedPhiInput() {
368+
result = this.getAPhiInput() and
369+
exists(BasicBlock incoming | incoming = this.getPredecessorBlockForPhiArgument(result) |
370+
not incoming.getLastNode().(RaisingNode).unlikelySuccessor(this.getDefinition())
371+
)
372+
}
373+
374+
/** Gets the incoming edges for a Phi node, pruned of unlikely edges. */
375+
private BasicBlockWithPointsTo getAPrunedPredecessorBlockForPhi() {
376+
result = this.getAPredecessorBlockForPhi() and
377+
not result.unlikelySuccessor(this.getDefinition().getBasicBlock())
378+
}
379+
380+
private predicate implicitlyDefined() {
381+
not exists(this.getDefinition()) and
382+
not py_ssa_phi(this, _) and
383+
exists(GlobalVariable var | this.getVariable() = var |
384+
globallyDefinedName(var.getId())
385+
or
386+
var.getId() = "__path__" and var.getScope().(Module).isPackageInit()
387+
)
388+
}
389+
390+
/** Whether this variable may be undefined */
391+
predicate maybeUndefined() {
392+
not exists(this.getDefinition()) and not py_ssa_phi(this, _) and not this.implicitlyDefined()
393+
or
394+
this.getDefinition().isDelete()
395+
or
396+
exists(SsaVariableWithPointsTo var | var = this.getAPrunedPhiInput() | var.maybeUndefined())
397+
or
398+
/*
399+
* For phi-nodes, there must be a corresponding phi-input for each control-flow
400+
* predecessor. Otherwise, the variable will be undefined on that incoming edge.
401+
* WARNING: the same phi-input may cover multiple predecessors, so this check
402+
* cannot be done by counting.
403+
*/
404+
405+
exists(BasicBlock incoming |
406+
reaches_end(incoming) and
407+
incoming = this.getAPrunedPredecessorBlockForPhi() and
408+
not this.getAPhiInput().getDefinition().getBasicBlock().dominates(incoming)
409+
)
410+
}
411+
412+
override string getAQlClass() { none() }
413+
}
414+
415+
private predicate reaches_end(BasicBlock b) {
416+
not exits_early(b) and
417+
(
418+
/* Entry point */
419+
not exists(BasicBlock prev | prev.getASuccessor() = b)
420+
or
421+
exists(BasicBlock prev | prev.getASuccessor() = b | reaches_end(prev))
422+
)
423+
}
424+
425+
private predicate exits_early(BasicBlock b) {
426+
exists(FunctionObject f |
427+
f.neverReturns() and
428+
f.getACall().getBasicBlock() = b
429+
)
430+
}

python/ql/lib/semmle/python/SSA.qll

Lines changed: 1 addition & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
/** SSA library */
22

33
import python
4-
private import LegacyPointsTo
54

65
/**
76
* A single static assignment variable.
@@ -62,14 +61,6 @@ class SsaVariable extends @py_ssa_var {
6261
)
6362
}
6463

65-
/** Gets an argument of the phi function defining this variable, pruned of unlikely edges. */
66-
SsaVariable getAPrunedPhiInput() {
67-
result = this.getAPhiInput() and
68-
exists(BasicBlock incoming | incoming = this.getPredecessorBlockForPhiArgument(result) |
69-
not incoming.getLastNode().(RaisingNode).unlikelySuccessor(this.getDefinition())
70-
)
71-
}
72-
7364
/** Gets a variable that ultimately defines this variable and is not itself defined by another variable */
7465
SsaVariable getAnUltimateDefinition() {
7566
result = this and not exists(this.getAPhiInput())
@@ -86,17 +77,11 @@ class SsaVariable extends @py_ssa_var {
8677
string getId() { result = this.getVariable().getId() }
8778

8879
/** Gets the incoming edges for a Phi node. */
89-
private BasicBlock getAPredecessorBlockForPhi() {
80+
BasicBlock getAPredecessorBlockForPhi() {
9081
exists(this.getAPhiInput()) and
9182
result.getASuccessor() = this.getDefinition().getBasicBlock()
9283
}
9384

94-
/** Gets the incoming edges for a Phi node, pruned of unlikely edges. */
95-
private BasicBlockWithPointsTo getAPrunedPredecessorBlockForPhi() {
96-
result = this.getAPredecessorBlockForPhi() and
97-
not result.unlikelySuccessor(this.getDefinition().getBasicBlock())
98-
}
99-
10085
/** Whether it is possible to reach a use of this variable without passing a definition */
10186
predicate reachableWithoutDefinition() {
10287
not exists(this.getDefinition()) and not py_ssa_phi(this, _)
@@ -116,38 +101,6 @@ class SsaVariable extends @py_ssa_var {
116101
)
117102
}
118103

119-
/** Whether this variable may be undefined */
120-
predicate maybeUndefined() {
121-
not exists(this.getDefinition()) and not py_ssa_phi(this, _) and not this.implicitlyDefined()
122-
or
123-
this.getDefinition().isDelete()
124-
or
125-
exists(SsaVariable var | var = this.getAPrunedPhiInput() | var.maybeUndefined())
126-
or
127-
/*
128-
* For phi-nodes, there must be a corresponding phi-input for each control-flow
129-
* predecessor. Otherwise, the variable will be undefined on that incoming edge.
130-
* WARNING: the same phi-input may cover multiple predecessors, so this check
131-
* cannot be done by counting.
132-
*/
133-
134-
exists(BasicBlock incoming |
135-
reaches_end(incoming) and
136-
incoming = this.getAPrunedPredecessorBlockForPhi() and
137-
not this.getAPhiInput().getDefinition().getBasicBlock().dominates(incoming)
138-
)
139-
}
140-
141-
private predicate implicitlyDefined() {
142-
not exists(this.getDefinition()) and
143-
not py_ssa_phi(this, _) and
144-
exists(GlobalVariable var | this.getVariable() = var |
145-
globallyDefinedName(var.getId())
146-
or
147-
var.getId() = "__path__" and var.getScope().(Module).isPackageInit()
148-
)
149-
}
150-
151104
/**
152105
* Gets the global variable that is accessed if this local is undefined.
153106
* Only applies to local variables in class scopes.
@@ -174,43 +127,6 @@ class SsaVariable extends @py_ssa_var {
174127
}
175128
}
176129

177-
private predicate reaches_end(BasicBlock b) {
178-
not exits_early(b) and
179-
(
180-
/* Entry point */
181-
not exists(BasicBlock prev | prev.getASuccessor() = b)
182-
or
183-
exists(BasicBlock prev | prev.getASuccessor() = b | reaches_end(prev))
184-
)
185-
}
186-
187-
private predicate exits_early(BasicBlock b) {
188-
exists(FunctionObject f |
189-
f.neverReturns() and
190-
f.getACall().getBasicBlock() = b
191-
)
192-
}
193-
194-
private predicate gettext_installed() {
195-
// Good enough (and fast) approximation
196-
exists(Module m | m.getName() = "gettext")
197-
}
198-
199-
private predicate builtin_constant(string name) {
200-
exists(Object::builtin(name))
201-
or
202-
name = "WindowsError"
203-
or
204-
name = "_" and gettext_installed()
205-
}
206-
207-
private predicate auto_name(string name) {
208-
name = "__file__" or name = "__builtins__" or name = "__name__"
209-
}
210-
211-
/** Whether this name is (almost) always defined, ie. it is a builtin or VM defined name */
212-
predicate globallyDefinedName(string name) { builtin_constant(name) or auto_name(name) }
213-
214130
/** An SSA variable that is backed by a global variable */
215131
class GlobalSsaVariable extends EssaVariable {
216132
GlobalSsaVariable() { this.getSourceVariable() instanceof GlobalVariable }

0 commit comments

Comments
 (0)