Skip to content

Commit 97f9920

Browse files
committed
Python: Move NameNode class in Flow.qll with other CFG classes.
1 parent 68da13c commit 97f9920

File tree

2 files changed

+143
-148
lines changed

2 files changed

+143
-148
lines changed

python/ql/src/semmle/python/Flow.qll

Lines changed: 143 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import python
2-
import semmle.python.flow.NameNode
32
private import semmle.python.pointsto.PointsTo
43

54
/* Note about matching parent and child nodes and CFG splitting:
@@ -961,10 +960,149 @@ class RaiseStmtNode extends ControlFlowNode {
961960

962961
}
963962

964-
private
965-
predicate defined_by(NameNode def, Variable v) {
966-
def.defines(v) or
967-
exists(NameNode p | defined_by(p, v) and p.getASuccessor() = def and not p.defines(v))
963+
/** A control flow node corresponding to a (plain variable) name expression, such as `var`.
964+
* `None`, `True` and `False` are excluded.
965+
*/
966+
class NameNode extends ControlFlowNode {
967+
968+
NameNode() {
969+
exists(Name n | py_flow_bb_node(this, n, _, _))
970+
or
971+
exists(PlaceHolder p | py_flow_bb_node(this, p, _, _))
972+
}
973+
974+
/** Whether this flow node defines the variable `v`. */
975+
predicate defines(Variable v) {
976+
exists(Name d | this.getNode() = d and d.defines(v))
977+
and not this.isLoad()
978+
}
979+
980+
/** Whether this flow node deletes the variable `v`. */
981+
predicate deletes(Variable v) {
982+
exists(Name d | this.getNode() = d and d.deletes(v))
983+
}
984+
985+
/** Whether this flow node uses the variable `v`. */
986+
predicate uses(Variable v) {
987+
this.isLoad() and exists(Name u | this.getNode() = u and u.uses(v))
988+
or
989+
exists(PlaceHolder u | this.getNode() = u and u.getVariable() = v and u.getCtx() instanceof Load)
990+
or
991+
Scopes::use_of_global_variable(this, v.getScope(), v.getId())
992+
}
993+
994+
string getId() {
995+
result = this.getNode().(Name).getId()
996+
or
997+
result = this.getNode().(PlaceHolder).getId()
998+
}
999+
1000+
/** Whether this is a use of a local variable. */
1001+
predicate isLocal() {
1002+
Scopes::local(this)
1003+
}
1004+
1005+
/** Whether this is a use of a non-local variable. */
1006+
predicate isNonLocal() {
1007+
Scopes::non_local(this)
1008+
}
1009+
1010+
/** Whether this is a use of a global (including builtin) variable. */
1011+
predicate isGlobal() {
1012+
Scopes::use_of_global_variable(this, _, _)
1013+
}
1014+
1015+
predicate isSelf() {
1016+
exists(SsaVariable selfvar |
1017+
selfvar.isSelf() and selfvar.getAUse() = this
1018+
)
1019+
}
1020+
1021+
}
1022+
1023+
/** A control flow node corresponding to a named constant, one of `None`, `True` or `False`. */
1024+
class NameConstantNode extends NameNode {
1025+
1026+
NameConstantNode() {
1027+
exists(NameConstant n | py_flow_bb_node(this, n, _, _))
1028+
}
1029+
1030+
override deprecated predicate defines(Variable v) { none() }
1031+
1032+
override deprecated predicate deletes(Variable v) { none() }
1033+
1034+
/* We ought to override uses as well, but that has
1035+
* a serious performance impact.
1036+
deprecated predicate uses(Variable v) { none() }
1037+
*/
1038+
}
1039+
1040+
private module Scopes {
1041+
1042+
private predicate fast_local(NameNode n) {
1043+
exists(FastLocalVariable v |
1044+
n.uses(v) and
1045+
v.getScope() = n.getScope()
1046+
)
1047+
}
1048+
1049+
predicate local(NameNode n) {
1050+
fast_local(n)
1051+
or
1052+
exists(SsaVariable var |
1053+
var.getAUse() = n and
1054+
n.getScope() instanceof Class and
1055+
exists(var.getDefinition())
1056+
)
1057+
}
1058+
1059+
predicate non_local(NameNode n) {
1060+
exists(FastLocalVariable flv |
1061+
flv.getALoad() = n.getNode() and
1062+
not flv.getScope() = n.getScope()
1063+
)
1064+
}
1065+
1066+
// magic is fine, but we get questionable join-ordering of it
1067+
pragma [nomagic]
1068+
predicate use_of_global_variable(NameNode n, Module scope, string name) {
1069+
n.isLoad() and
1070+
not non_local(n)
1071+
and
1072+
not exists(SsaVariable var |
1073+
var.getAUse() = n |
1074+
var.getVariable() instanceof FastLocalVariable
1075+
or
1076+
n.getScope() instanceof Class and
1077+
not maybe_undefined(var)
1078+
)
1079+
and name = n.getId()
1080+
and scope = n.getEnclosingModule()
1081+
}
1082+
1083+
private predicate maybe_defined(SsaVariable var) {
1084+
exists(var.getDefinition()) and not py_ssa_phi(var, _) and not var.getDefinition().isDelete()
1085+
or
1086+
exists(SsaVariable input |
1087+
input = var.getAPhiInput() |
1088+
maybe_defined(input)
1089+
)
1090+
}
1091+
1092+
private predicate maybe_undefined(SsaVariable var) {
1093+
not exists(var.getDefinition()) and not py_ssa_phi(var, _)
1094+
or
1095+
var.getDefinition().isDelete()
1096+
or
1097+
maybe_undefined(var.getAPhiInput())
1098+
or
1099+
exists(BasicBlock incoming |
1100+
exists(var.getAPhiInput()) and
1101+
incoming.getASuccessor() = var.getDefinition().getBasicBlock() and
1102+
not var.getAPhiInput().getDefinition().getBasicBlock().dominates(incoming)
1103+
)
1104+
}
1105+
9681106
}
9691107

9701108
/** A basic block (ignoring exceptional flow edges to scope exit) */

python/ql/src/semmle/python/flow/NameNode.qll

Lines changed: 0 additions & 143 deletions
This file was deleted.

0 commit comments

Comments
 (0)