mirror of
https://github.com/github/codeql.git
synced 2025-12-16 08:43:11 +01:00
Python: Remove points-to from SSA.ql
Happily, this was not as deeply entwined as it looked at first glance.
This commit is contained in:
@@ -340,3 +340,91 @@ Object getLiteralObject(ImmutableLiteral l) {
|
||||
name_consts(l, "None") and
|
||||
result = theNoneObject()
|
||||
}
|
||||
|
||||
private predicate gettext_installed() {
|
||||
// Good enough (and fast) approximation
|
||||
exists(Module m | m.getName() = "gettext")
|
||||
}
|
||||
|
||||
private predicate builtin_constant(string name) {
|
||||
exists(Object::builtin(name))
|
||||
or
|
||||
name = "WindowsError"
|
||||
or
|
||||
name = "_" and gettext_installed()
|
||||
}
|
||||
|
||||
/** Whether this name is (almost) always defined, ie. it is a builtin or VM defined name */
|
||||
predicate globallyDefinedName(string name) { builtin_constant(name) or auto_name(name) }
|
||||
|
||||
private predicate auto_name(string name) {
|
||||
name = "__file__" or name = "__builtins__" or name = "__name__"
|
||||
}
|
||||
|
||||
/** An extension of `SsaVariable` that provides points-to related methods. */
|
||||
class SsaVariableWithPointsTo extends SsaVariable {
|
||||
/** Gets an argument of the phi function defining this variable, pruned of unlikely edges. */
|
||||
SsaVariable getAPrunedPhiInput() {
|
||||
result = this.getAPhiInput() and
|
||||
exists(BasicBlock incoming | incoming = this.getPredecessorBlockForPhiArgument(result) |
|
||||
not incoming.getLastNode().(RaisingNode).unlikelySuccessor(this.getDefinition())
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the incoming edges for a Phi node, pruned of unlikely edges. */
|
||||
private BasicBlockWithPointsTo getAPrunedPredecessorBlockForPhi() {
|
||||
result = this.getAPredecessorBlockForPhi() and
|
||||
not result.unlikelySuccessor(this.getDefinition().getBasicBlock())
|
||||
}
|
||||
|
||||
private predicate implicitlyDefined() {
|
||||
not exists(this.getDefinition()) and
|
||||
not py_ssa_phi(this, _) and
|
||||
exists(GlobalVariable var | this.getVariable() = var |
|
||||
globallyDefinedName(var.getId())
|
||||
or
|
||||
var.getId() = "__path__" and var.getScope().(Module).isPackageInit()
|
||||
)
|
||||
}
|
||||
|
||||
/** Whether this variable may be undefined */
|
||||
predicate maybeUndefined() {
|
||||
not exists(this.getDefinition()) and not py_ssa_phi(this, _) and not this.implicitlyDefined()
|
||||
or
|
||||
this.getDefinition().isDelete()
|
||||
or
|
||||
exists(SsaVariableWithPointsTo var | var = this.getAPrunedPhiInput() | var.maybeUndefined())
|
||||
or
|
||||
/*
|
||||
* For phi-nodes, there must be a corresponding phi-input for each control-flow
|
||||
* predecessor. Otherwise, the variable will be undefined on that incoming edge.
|
||||
* WARNING: the same phi-input may cover multiple predecessors, so this check
|
||||
* cannot be done by counting.
|
||||
*/
|
||||
|
||||
exists(BasicBlock incoming |
|
||||
reaches_end(incoming) and
|
||||
incoming = this.getAPrunedPredecessorBlockForPhi() and
|
||||
not this.getAPhiInput().getDefinition().getBasicBlock().dominates(incoming)
|
||||
)
|
||||
}
|
||||
|
||||
override string getAQlClass() { none() }
|
||||
}
|
||||
|
||||
private predicate reaches_end(BasicBlock b) {
|
||||
not exits_early(b) and
|
||||
(
|
||||
/* Entry point */
|
||||
not exists(BasicBlock prev | prev.getASuccessor() = b)
|
||||
or
|
||||
exists(BasicBlock prev | prev.getASuccessor() = b | reaches_end(prev))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate exits_early(BasicBlock b) {
|
||||
exists(FunctionObject f |
|
||||
f.neverReturns() and
|
||||
f.getACall().getBasicBlock() = b
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/** SSA library */
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
|
||||
/**
|
||||
* A single static assignment variable.
|
||||
@@ -62,14 +61,6 @@ class SsaVariable extends @py_ssa_var {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets an argument of the phi function defining this variable, pruned of unlikely edges. */
|
||||
SsaVariable getAPrunedPhiInput() {
|
||||
result = this.getAPhiInput() and
|
||||
exists(BasicBlock incoming | incoming = this.getPredecessorBlockForPhiArgument(result) |
|
||||
not incoming.getLastNode().(RaisingNode).unlikelySuccessor(this.getDefinition())
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a variable that ultimately defines this variable and is not itself defined by another variable */
|
||||
SsaVariable getAnUltimateDefinition() {
|
||||
result = this and not exists(this.getAPhiInput())
|
||||
@@ -86,17 +77,11 @@ class SsaVariable extends @py_ssa_var {
|
||||
string getId() { result = this.getVariable().getId() }
|
||||
|
||||
/** Gets the incoming edges for a Phi node. */
|
||||
private BasicBlock getAPredecessorBlockForPhi() {
|
||||
BasicBlock getAPredecessorBlockForPhi() {
|
||||
exists(this.getAPhiInput()) and
|
||||
result.getASuccessor() = this.getDefinition().getBasicBlock()
|
||||
}
|
||||
|
||||
/** Gets the incoming edges for a Phi node, pruned of unlikely edges. */
|
||||
private BasicBlockWithPointsTo getAPrunedPredecessorBlockForPhi() {
|
||||
result = this.getAPredecessorBlockForPhi() and
|
||||
not result.unlikelySuccessor(this.getDefinition().getBasicBlock())
|
||||
}
|
||||
|
||||
/** Whether it is possible to reach a use of this variable without passing a definition */
|
||||
predicate reachableWithoutDefinition() {
|
||||
not exists(this.getDefinition()) and not py_ssa_phi(this, _)
|
||||
@@ -116,38 +101,6 @@ class SsaVariable extends @py_ssa_var {
|
||||
)
|
||||
}
|
||||
|
||||
/** Whether this variable may be undefined */
|
||||
predicate maybeUndefined() {
|
||||
not exists(this.getDefinition()) and not py_ssa_phi(this, _) and not this.implicitlyDefined()
|
||||
or
|
||||
this.getDefinition().isDelete()
|
||||
or
|
||||
exists(SsaVariable var | var = this.getAPrunedPhiInput() | var.maybeUndefined())
|
||||
or
|
||||
/*
|
||||
* For phi-nodes, there must be a corresponding phi-input for each control-flow
|
||||
* predecessor. Otherwise, the variable will be undefined on that incoming edge.
|
||||
* WARNING: the same phi-input may cover multiple predecessors, so this check
|
||||
* cannot be done by counting.
|
||||
*/
|
||||
|
||||
exists(BasicBlock incoming |
|
||||
reaches_end(incoming) and
|
||||
incoming = this.getAPrunedPredecessorBlockForPhi() and
|
||||
not this.getAPhiInput().getDefinition().getBasicBlock().dominates(incoming)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate implicitlyDefined() {
|
||||
not exists(this.getDefinition()) and
|
||||
not py_ssa_phi(this, _) and
|
||||
exists(GlobalVariable var | this.getVariable() = var |
|
||||
globallyDefinedName(var.getId())
|
||||
or
|
||||
var.getId() = "__path__" and var.getScope().(Module).isPackageInit()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the global variable that is accessed if this local is undefined.
|
||||
* Only applies to local variables in class scopes.
|
||||
@@ -174,43 +127,6 @@ class SsaVariable extends @py_ssa_var {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate reaches_end(BasicBlock b) {
|
||||
not exits_early(b) and
|
||||
(
|
||||
/* Entry point */
|
||||
not exists(BasicBlock prev | prev.getASuccessor() = b)
|
||||
or
|
||||
exists(BasicBlock prev | prev.getASuccessor() = b | reaches_end(prev))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate exits_early(BasicBlock b) {
|
||||
exists(FunctionObject f |
|
||||
f.neverReturns() and
|
||||
f.getACall().getBasicBlock() = b
|
||||
)
|
||||
}
|
||||
|
||||
private predicate gettext_installed() {
|
||||
// Good enough (and fast) approximation
|
||||
exists(Module m | m.getName() = "gettext")
|
||||
}
|
||||
|
||||
private predicate builtin_constant(string name) {
|
||||
exists(Object::builtin(name))
|
||||
or
|
||||
name = "WindowsError"
|
||||
or
|
||||
name = "_" and gettext_installed()
|
||||
}
|
||||
|
||||
private predicate auto_name(string name) {
|
||||
name = "__file__" or name = "__builtins__" or name = "__name__"
|
||||
}
|
||||
|
||||
/** Whether this name is (almost) always defined, ie. it is a builtin or VM defined name */
|
||||
predicate globallyDefinedName(string name) { builtin_constant(name) or auto_name(name) }
|
||||
|
||||
/** An SSA variable that is backed by a global variable */
|
||||
class GlobalSsaVariable extends EssaVariable {
|
||||
GlobalSsaVariable() { this.getSourceVariable() instanceof GlobalVariable }
|
||||
|
||||
Reference in New Issue
Block a user