mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Python ESSA: Move variable definitions into new file and unify 'generic' and 'python specific' parts.
This commit is contained in:
395
python/ql/src/semmle/python/essa/Definitions.qll
Normal file
395
python/ql/src/semmle/python/essa/Definitions.qll
Normal file
@@ -0,0 +1,395 @@
|
||||
import python
|
||||
|
||||
/* Classification of variables. These should be non-overlapping and complete.
|
||||
*
|
||||
* Function local variables - Non escaping variables in a function, except 'self'
|
||||
* Self variables - The 'self' variable for a method.
|
||||
* Class local variables - Local variables declared in a class
|
||||
* Non-local variables - Escaping variables in a function
|
||||
* Built-in variables - Global variables with no definition
|
||||
* Non-escaping globals -- Global variables that have definitions and all of those definitions are in the module scope
|
||||
* Escaping globals -- Global variables that have definitions and at least one of those definitions is in another scope.
|
||||
*/
|
||||
|
||||
/** A source language variable, to be converted into a set of SSA variables. */
|
||||
abstract class SsaSourceVariable extends @py_variable {
|
||||
|
||||
SsaSourceVariable() {
|
||||
/* Exclude `True`, `False` and `None` */
|
||||
not this.(Variable).getALoad() instanceof NameConstant
|
||||
}
|
||||
|
||||
/** Gets the name of this variable */
|
||||
string getName() {
|
||||
variable(this, _, result)
|
||||
}
|
||||
|
||||
Scope getScope() {
|
||||
variable(this, result, _)
|
||||
}
|
||||
|
||||
/** Gets an implicit use of this variable */
|
||||
abstract ControlFlowNode getAnImplicitUse();
|
||||
|
||||
abstract ControlFlowNode getScopeEntryDefinition();
|
||||
|
||||
string toString() {
|
||||
result = "SsaSourceVariable " + this.getName()
|
||||
}
|
||||
|
||||
/** Gets a use of this variable, either explicit or implicit. */
|
||||
ControlFlowNode getAUse() {
|
||||
result = this.getASourceUse()
|
||||
or
|
||||
result = this.getAnImplicitUse()
|
||||
or
|
||||
/* `import *` is a definition of *all* variables, so must be a use as well, for pass-through
|
||||
* once we have established that a variable is not redefined.
|
||||
*/
|
||||
SsaSource::import_star_refinement(this, result, _)
|
||||
or
|
||||
/* Add a use at the end of scope for all variables to keep them live
|
||||
* This is necessary for taint-tracking.
|
||||
*/
|
||||
result = this.getScope().getANormalExit()
|
||||
}
|
||||
|
||||
/** Holds if `def` defines an ESSA variable for this variable. */
|
||||
predicate hasDefiningNode(ControlFlowNode def) {
|
||||
def = this.getScopeEntryDefinition()
|
||||
or
|
||||
SsaSource::assignment_definition(this, def, _)
|
||||
or
|
||||
SsaSource::multi_assignment_definition(this, def, _, _)
|
||||
or
|
||||
SsaSource::deletion_definition(this, def)
|
||||
or
|
||||
SsaSource::init_module_submodule_defn(this, def)
|
||||
or
|
||||
SsaSource::parameter_definition(this, def)
|
||||
or
|
||||
SsaSource::exception_capture(this, def)
|
||||
or
|
||||
SsaSource::with_definition(this, def)
|
||||
}
|
||||
|
||||
/** Holds if `def` defines an ESSA variable for this variable in such a way
|
||||
* that the new variable is a refinement in some way of the variable used at `use`.
|
||||
*/
|
||||
predicate hasRefinement(ControlFlowNode use, ControlFlowNode def) {
|
||||
this.hasDefiningNode(_) and /* Can't have a refinement unless there is a definition */
|
||||
refinement(this, use, def)
|
||||
}
|
||||
|
||||
/** Holds if the edge `pred`->`succ` defines an ESSA variable for this variable in such a way
|
||||
* that the new variable is a refinement in some way of the variable used at `use`.
|
||||
*/
|
||||
predicate hasRefinementEdge(ControlFlowNode use, BasicBlock pred, BasicBlock succ) {
|
||||
test_contains(pred.getLastNode(), use) and
|
||||
use.(NameNode).uses(this) and
|
||||
(pred.getAFalseSuccessor() = succ or pred.getATrueSuccessor() = succ) and
|
||||
/* There is a store to this variable -- We don't want to refine builtins */
|
||||
exists(this.(Variable).getAStore())
|
||||
}
|
||||
|
||||
/** Gets a use of this variable that corresponds to an explicit use in the source. */
|
||||
ControlFlowNode getASourceUse() {
|
||||
result.(NameNode).uses(this)
|
||||
or
|
||||
result.(NameNode).deletes(this)
|
||||
}
|
||||
|
||||
abstract CallNode redefinedAtCallSite();
|
||||
|
||||
}
|
||||
|
||||
private predicate refinement(SsaSourceVariable v, ControlFlowNode use, ControlFlowNode def) {
|
||||
SsaSource::import_star_refinement(v, use, def)
|
||||
or
|
||||
SsaSource::attribute_assignment_refinement(v, use, def)
|
||||
or
|
||||
SsaSource::argument_refinement(v, use, def)
|
||||
or
|
||||
SsaSource::attribute_deletion_refinement(v, use, def)
|
||||
or
|
||||
SsaSource::test_refinement(v, use, def)
|
||||
or
|
||||
SsaSource::method_call_refinement(v, use, def)
|
||||
or
|
||||
def = v.redefinedAtCallSite() and def = use
|
||||
}
|
||||
|
||||
|
||||
class FunctionLocalVariable extends SsaSourceVariable {
|
||||
|
||||
FunctionLocalVariable() {
|
||||
this.(LocalVariable).getScope() instanceof Function and
|
||||
not this instanceof NonLocalVariable
|
||||
}
|
||||
|
||||
override ControlFlowNode getAnImplicitUse() {
|
||||
this.(Variable).isSelf() and this.(Variable).getScope().getANormalExit() = result
|
||||
}
|
||||
|
||||
override ControlFlowNode getScopeEntryDefinition() {
|
||||
exists(Scope s |
|
||||
s.getEntryNode() = result |
|
||||
s = this.(LocalVariable).getScope() and
|
||||
not this.(LocalVariable).isParameter()
|
||||
or
|
||||
s != this.(LocalVariable).getScope() and
|
||||
s = this.(LocalVariable).getALoad().getScope()
|
||||
)
|
||||
}
|
||||
|
||||
override CallNode redefinedAtCallSite() { none() }
|
||||
|
||||
}
|
||||
|
||||
class NonLocalVariable extends SsaSourceVariable {
|
||||
|
||||
NonLocalVariable() {
|
||||
exists(Function f |
|
||||
this.(LocalVariable).getScope() = f and
|
||||
this.(LocalVariable).getAStore().getScope() != f
|
||||
)
|
||||
}
|
||||
|
||||
override ControlFlowNode getAnImplicitUse() {
|
||||
result.(CallNode).getScope().getScope*() = this.(LocalVariable).getScope()
|
||||
}
|
||||
|
||||
override ControlFlowNode getScopeEntryDefinition() {
|
||||
exists(Function f |
|
||||
f.getScope+() = this.(LocalVariable).getScope() and
|
||||
f.getEntryNode() = result
|
||||
)
|
||||
or
|
||||
not this.(LocalVariable).isParameter() and
|
||||
this.(LocalVariable).getScope().getEntryNode() = result
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
Scope scope_as_local_variable() {
|
||||
result = this.(LocalVariable).getScope()
|
||||
}
|
||||
|
||||
override CallNode redefinedAtCallSite() {
|
||||
result.getScope().getScope*() = this.scope_as_local_variable()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ClassLocalVariable extends SsaSourceVariable {
|
||||
|
||||
ClassLocalVariable() {
|
||||
this.(LocalVariable).getScope() instanceof Class
|
||||
}
|
||||
|
||||
override ControlFlowNode getAnImplicitUse() {
|
||||
none()
|
||||
}
|
||||
|
||||
override ControlFlowNode getScopeEntryDefinition() {
|
||||
result = this.(LocalVariable).getScope().getEntryNode()
|
||||
}
|
||||
|
||||
override CallNode redefinedAtCallSite() { none() }
|
||||
|
||||
}
|
||||
|
||||
class BuiltinVariable extends SsaSourceVariable {
|
||||
|
||||
BuiltinVariable() {
|
||||
this instanceof GlobalVariable and
|
||||
not exists(this.(Variable).getAStore()) and
|
||||
not this.(Variable).getId() = "__name__" and
|
||||
not this.(Variable).getId() = "__package__" and
|
||||
not exists(ImportStar is | is.getScope() = this.(Variable).getScope())
|
||||
}
|
||||
|
||||
override ControlFlowNode getAnImplicitUse() {
|
||||
none()
|
||||
}
|
||||
|
||||
override ControlFlowNode getScopeEntryDefinition() {
|
||||
none()
|
||||
}
|
||||
|
||||
override CallNode redefinedAtCallSite() { none() }
|
||||
|
||||
}
|
||||
|
||||
class ModuleVariable extends SsaSourceVariable {
|
||||
|
||||
ModuleVariable() {
|
||||
this instanceof GlobalVariable and
|
||||
(
|
||||
exists(this.(Variable).getAStore())
|
||||
or
|
||||
this.(Variable).getId() = "__name__"
|
||||
or
|
||||
this.(Variable).getId() = "__package__"
|
||||
or
|
||||
exists(ImportStar is | is.getScope() = this.(Variable).getScope())
|
||||
)
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
CallNode global_variable_callnode() {
|
||||
result.getScope() = this.(GlobalVariable).getScope()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
ImportMemberNode global_variable_import() {
|
||||
result.getScope() = this.(GlobalVariable).getScope() and
|
||||
import_from_dot_in_init(result.(ImportMemberNode).getModule(this.getName()))
|
||||
}
|
||||
|
||||
override ControlFlowNode getAnImplicitUse() {
|
||||
result = global_variable_callnode()
|
||||
or
|
||||
result = global_variable_import()
|
||||
or
|
||||
exists(ImportTimeScope scope |
|
||||
scope.entryEdge(result, _) |
|
||||
this = scope.getOuterVariable(_) or
|
||||
this.(Variable).getAUse().getScope() = scope
|
||||
)
|
||||
or
|
||||
/* For implicit use of __metaclass__ when constructing class */
|
||||
exists(Class c |
|
||||
class_with_global_metaclass(c, this) and
|
||||
c.(ImportTimeScope).entryEdge(result, _)
|
||||
)
|
||||
or
|
||||
exists(ImportTimeScope s |
|
||||
result = s.getANormalExit() and this.(Variable).getScope() = s and
|
||||
implicit_definition(this)
|
||||
)
|
||||
}
|
||||
|
||||
override ControlFlowNode getScopeEntryDefinition() {
|
||||
exists(Scope s |
|
||||
s.getEntryNode() = result |
|
||||
/* Module entry point */
|
||||
this.(GlobalVariable).getScope() = s
|
||||
or
|
||||
/* For implicit use of __metaclass__ when constructing class */
|
||||
class_with_global_metaclass(s, this)
|
||||
or
|
||||
/* Variable is used in scope */
|
||||
this.(GlobalVariable).getAUse().getScope() = s
|
||||
)
|
||||
or
|
||||
exists(ImportTimeScope scope |
|
||||
scope.entryEdge(_, result) |
|
||||
this = scope.getOuterVariable(_) or
|
||||
this.(Variable).getAUse().getScope() = scope
|
||||
)
|
||||
}
|
||||
|
||||
override CallNode redefinedAtCallSite() { none() }
|
||||
|
||||
}
|
||||
|
||||
class NonEscapingGlobalVariable extends ModuleVariable {
|
||||
|
||||
NonEscapingGlobalVariable() {
|
||||
this instanceof GlobalVariable and
|
||||
exists(this.(Variable).getAStore()) and
|
||||
not variable_or_attribute_defined_out_of_scope(this)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class EscapingGlobalVariable extends ModuleVariable {
|
||||
|
||||
EscapingGlobalVariable() {
|
||||
this instanceof GlobalVariable and exists(this.(Variable).getAStore()) and variable_or_attribute_defined_out_of_scope(this)
|
||||
}
|
||||
|
||||
override ControlFlowNode getAnImplicitUse() {
|
||||
result = ModuleVariable.super.getAnImplicitUse()
|
||||
or
|
||||
result.(CallNode).getScope().getScope+() = this.(GlobalVariable).getScope()
|
||||
or
|
||||
result = this.innerScope().getANormalExit()
|
||||
}
|
||||
|
||||
private Scope innerScope() {
|
||||
result.getScope+() = this.(GlobalVariable).getScope() and
|
||||
not result instanceof ImportTimeScope
|
||||
}
|
||||
|
||||
override ControlFlowNode getScopeEntryDefinition() {
|
||||
result = ModuleVariable.super.getScopeEntryDefinition()
|
||||
or
|
||||
result = this.innerScope().getEntryNode()
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
Scope scope_as_global_variable() {
|
||||
result = this.(GlobalVariable).getScope()
|
||||
}
|
||||
|
||||
override CallNode redefinedAtCallSite() {
|
||||
result.(CallNode).getScope().getScope*() = this.scope_as_global_variable()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class EscapingAssignmentGlobalVariable extends EscapingGlobalVariable {
|
||||
|
||||
EscapingAssignmentGlobalVariable() {
|
||||
exists(NameNode n | n.defines(this) and not n.getScope() = this.getScope())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class SpecialSsaSourceVariable extends SsaSourceVariable {
|
||||
|
||||
SpecialSsaSourceVariable() {
|
||||
variable(this, _, "*") or variable(this, _, "$")
|
||||
}
|
||||
|
||||
override ControlFlowNode getAnImplicitUse() {
|
||||
exists(ImportTimeScope s |
|
||||
result = s.getANormalExit() and this.getScope() = s
|
||||
)
|
||||
}
|
||||
|
||||
override ControlFlowNode getScopeEntryDefinition() {
|
||||
/* Module entry point */
|
||||
this.getScope().getEntryNode() = result
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
Scope scope_as_global_variable() {
|
||||
result = this.(GlobalVariable).getScope()
|
||||
}
|
||||
|
||||
override CallNode redefinedAtCallSite() {
|
||||
result.(CallNode).getScope().getScope*() = this.scope_as_global_variable()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Holds if this variable is implicitly defined */
|
||||
private predicate implicit_definition(Variable v) {
|
||||
v.getId() = "*" or v.getId() = "$"
|
||||
or
|
||||
exists(ImportStar is | is.getScope() = v.getScope())
|
||||
}
|
||||
|
||||
private predicate variable_or_attribute_defined_out_of_scope(Variable v) {
|
||||
exists(NameNode n | n.defines(v) and not n.getScope() = v.getScope())
|
||||
or
|
||||
exists(AttrNode a | a.isStore() and a.getObject() = v.getAUse() and not a.getScope() = v.getScope())
|
||||
}
|
||||
|
||||
private predicate class_with_global_metaclass(Class cls, GlobalVariable metaclass) {
|
||||
metaclass.getId() = "__metaclass__" and major_version() = 2 and
|
||||
cls.getEnclosingModule() = metaclass.getScope()
|
||||
}
|
||||
@@ -4,77 +4,8 @@
|
||||
|
||||
import python
|
||||
private import SsaCompute
|
||||
import semmle.python.essa.Definitions
|
||||
|
||||
/* The general intent of this code is to assume only the following interfaces,
|
||||
* although several Python-specific parts may have crept in.
|
||||
*
|
||||
* SsaSourceVariable { ... } // See interface below
|
||||
*
|
||||
*
|
||||
* BasicBlock {
|
||||
*
|
||||
* ControlFlowNode getNode(int n);
|
||||
*
|
||||
* BasicBlock getImmediateDominator();
|
||||
*
|
||||
* BasicBlock getAPredecessor();
|
||||
*
|
||||
* BasicBlock getATrueSuccessor();
|
||||
*
|
||||
* BasicBlock getAFalseSuccessor();
|
||||
*
|
||||
* predicate dominanceFrontier(BasicBlock other);
|
||||
*
|
||||
* predicate strictlyDominates(BasicBlock other);
|
||||
*
|
||||
* predicate hasLocationInfo(string f, int bl, int bc, int el, int ec);
|
||||
*
|
||||
* }
|
||||
*
|
||||
* ControlFlowNode {
|
||||
*
|
||||
* Location getLocation();
|
||||
*
|
||||
* BasicBlock getBasicBlock();
|
||||
*
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/** A source language variable, to be converted into a set of SSA variables. */
|
||||
abstract class SsaSourceVariable extends @py_variable {
|
||||
|
||||
/** Gets the name of this variable */
|
||||
abstract string getName();
|
||||
|
||||
string toString() {
|
||||
result = "SsaSourceVariable " + this.getName()
|
||||
}
|
||||
|
||||
/** Gets a use of this variable, either explicit or implicit. */
|
||||
abstract ControlFlowNode getAUse();
|
||||
|
||||
/** Holds if `def` defines an ESSA variable for this variable. */
|
||||
abstract predicate hasDefiningNode(ControlFlowNode def);
|
||||
|
||||
/** Holds if the edge `pred`->`succ` defines an ESSA variable for this variable. */
|
||||
abstract predicate hasDefiningEdge(BasicBlock pred, BasicBlock succ);
|
||||
|
||||
/** Holds if `def` defines an ESSA variable for this variable in such a way
|
||||
* that the new variable is a refinement in some way of the variable used at `use`.
|
||||
*/
|
||||
abstract predicate hasRefinement(ControlFlowNode use, ControlFlowNode def);
|
||||
|
||||
/** Holds if the edge `pred`->`succ` defines an ESSA variable for this variable in such a way
|
||||
* that the new variable is a refinement in some way of the variable used at `use`.
|
||||
*/
|
||||
abstract predicate hasRefinementEdge(ControlFlowNode use, BasicBlock pred, BasicBlock succ);
|
||||
|
||||
/** Gets a use of this variable that corresponds to an explicit use in the source. */
|
||||
abstract ControlFlowNode getASourceUse();
|
||||
|
||||
}
|
||||
|
||||
/** An (enhanced) SSA variable derived from `SsaSourceVariable`. */
|
||||
class EssaVariable extends TEssaDefinition {
|
||||
@@ -730,7 +661,7 @@ class DeletionDefinition extends EssaNodeDefinition {
|
||||
class ScopeEntryDefinition extends EssaNodeDefinition {
|
||||
|
||||
ScopeEntryDefinition() {
|
||||
this.getDefiningNode() = this.getSourceVariable().(PythonSsaSourceVariable).getScopeEntryDefinition() and
|
||||
this.getDefiningNode() = this.getSourceVariable().getScopeEntryDefinition() and
|
||||
not this instanceof ImplicitSubModuleDefinition
|
||||
}
|
||||
|
||||
@@ -851,7 +782,7 @@ class CallsiteRefinement extends EssaNodeRefinement {
|
||||
}
|
||||
|
||||
CallsiteRefinement() {
|
||||
exists(PythonSsaSourceVariable var, ControlFlowNode defn |
|
||||
exists(SsaSourceVariable var, ControlFlowNode defn |
|
||||
defn = var.redefinedAtCallSite() and
|
||||
this.definedBy(var, defn) and
|
||||
not this instanceof ArgumentRefinement and
|
||||
|
||||
@@ -6,371 +6,7 @@ import python
|
||||
private import semmle.python.pointsto.Base
|
||||
|
||||
|
||||
/* Classification of variables. These should be non-overlapping and complete.
|
||||
*
|
||||
* Function local variables - Non escaping variables in a function, except 'self'
|
||||
* Self variables - The 'self' variable for a method.
|
||||
* Class local variables - Local variables declared in a class
|
||||
* Non-local variables - Escaping variables in a function
|
||||
* Built-in variables - Global variables with no definition
|
||||
* Non-escaping globals -- Global variables that have definitions and all of those definitions are in the module scope
|
||||
* Escaping globals -- Global variables that have definitions and at least one of those definitions is in another scope.
|
||||
*/
|
||||
|
||||
/** Python specific version of `SsaSourceVariable`. */
|
||||
abstract class PythonSsaSourceVariable extends SsaSourceVariable {
|
||||
|
||||
PythonSsaSourceVariable() {
|
||||
/* Exclude `True`, `False` and `None` */
|
||||
not this.(Variable).getALoad() instanceof NameConstant
|
||||
}
|
||||
|
||||
override string getName() {
|
||||
variable(this, _, result)
|
||||
}
|
||||
|
||||
Scope getScope() {
|
||||
variable(this, result, _)
|
||||
}
|
||||
|
||||
abstract ControlFlowNode getAnImplicitUse();
|
||||
|
||||
abstract ControlFlowNode getScopeEntryDefinition();
|
||||
|
||||
override ControlFlowNode getAUse() {
|
||||
result = this.getASourceUse()
|
||||
or
|
||||
result = this.getAnImplicitUse()
|
||||
or
|
||||
/* `import *` is a definition of *all* variables, so must be a use as well, for pass-through
|
||||
* once we have established that a variable is not redefined.
|
||||
*/
|
||||
SsaSource::import_star_refinement(this, result, _)
|
||||
or
|
||||
/* Add a use at the end of scope for all variables to keep them live
|
||||
* This is necessary for taint-tracking.
|
||||
*/
|
||||
result = this.getScope().getANormalExit()
|
||||
}
|
||||
|
||||
override predicate hasDefiningNode(ControlFlowNode def) {
|
||||
def = this.getScopeEntryDefinition()
|
||||
or
|
||||
SsaSource::assignment_definition(this, def, _)
|
||||
or
|
||||
SsaSource::multi_assignment_definition(this, def, _, _)
|
||||
or
|
||||
SsaSource::deletion_definition(this, def)
|
||||
or
|
||||
SsaSource::init_module_submodule_defn(this, def)
|
||||
or
|
||||
SsaSource::parameter_definition(this, def)
|
||||
or
|
||||
SsaSource::exception_capture(this, def)
|
||||
or
|
||||
SsaSource::with_definition(this, def)
|
||||
}
|
||||
|
||||
override predicate hasDefiningEdge(BasicBlock pred, BasicBlock succ) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasRefinement(ControlFlowNode use, ControlFlowNode def) {
|
||||
this.hasDefiningNode(_) and /* Can't have a refinement unless there is a definition */
|
||||
refinement(this, use, def)
|
||||
}
|
||||
|
||||
override predicate hasRefinementEdge(ControlFlowNode use, BasicBlock pred, BasicBlock succ) {
|
||||
test_contains(pred.getLastNode(), use) and
|
||||
use.(NameNode).uses(this) and
|
||||
(pred.getAFalseSuccessor() = succ or pred.getATrueSuccessor() = succ) and
|
||||
/* There is a store to this variable -- We don't want to refine builtins */
|
||||
exists(this.(Variable).getAStore())
|
||||
}
|
||||
override ControlFlowNode getASourceUse() {
|
||||
result.(NameNode).uses(this)
|
||||
or
|
||||
result.(NameNode).deletes(this)
|
||||
}
|
||||
|
||||
abstract CallNode redefinedAtCallSite();
|
||||
|
||||
}
|
||||
|
||||
class FunctionLocalVariable extends PythonSsaSourceVariable {
|
||||
|
||||
FunctionLocalVariable() {
|
||||
this.(LocalVariable).getScope() instanceof Function and
|
||||
not this instanceof NonLocalVariable
|
||||
}
|
||||
|
||||
override ControlFlowNode getAnImplicitUse() {
|
||||
this.(Variable).isSelf() and this.(Variable).getScope().getANormalExit() = result
|
||||
}
|
||||
|
||||
override ControlFlowNode getScopeEntryDefinition() {
|
||||
exists(Scope s |
|
||||
s.getEntryNode() = result |
|
||||
s = this.(LocalVariable).getScope() and
|
||||
not this.(LocalVariable).isParameter()
|
||||
or
|
||||
s != this.(LocalVariable).getScope() and
|
||||
s = this.(LocalVariable).getALoad().getScope()
|
||||
)
|
||||
}
|
||||
|
||||
override CallNode redefinedAtCallSite() { none() }
|
||||
|
||||
}
|
||||
|
||||
class NonLocalVariable extends PythonSsaSourceVariable {
|
||||
|
||||
NonLocalVariable() {
|
||||
exists(Function f |
|
||||
this.(LocalVariable).getScope() = f and
|
||||
this.(LocalVariable).getAStore().getScope() != f
|
||||
)
|
||||
}
|
||||
|
||||
override ControlFlowNode getAnImplicitUse() {
|
||||
result.(CallNode).getScope().getScope*() = this.(LocalVariable).getScope()
|
||||
}
|
||||
|
||||
override ControlFlowNode getScopeEntryDefinition() {
|
||||
exists(Function f |
|
||||
f.getScope+() = this.(LocalVariable).getScope() and
|
||||
f.getEntryNode() = result
|
||||
)
|
||||
or
|
||||
not this.(LocalVariable).isParameter() and
|
||||
this.(LocalVariable).getScope().getEntryNode() = result
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
Scope scope_as_local_variable() {
|
||||
result = this.(LocalVariable).getScope()
|
||||
}
|
||||
|
||||
override CallNode redefinedAtCallSite() {
|
||||
result.getScope().getScope*() = this.scope_as_local_variable()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ClassLocalVariable extends PythonSsaSourceVariable {
|
||||
|
||||
ClassLocalVariable() {
|
||||
this.(LocalVariable).getScope() instanceof Class
|
||||
}
|
||||
|
||||
override ControlFlowNode getAnImplicitUse() {
|
||||
none()
|
||||
}
|
||||
|
||||
override ControlFlowNode getScopeEntryDefinition() {
|
||||
result = this.(LocalVariable).getScope().getEntryNode()
|
||||
}
|
||||
|
||||
override CallNode redefinedAtCallSite() { none() }
|
||||
|
||||
}
|
||||
|
||||
class BuiltinVariable extends PythonSsaSourceVariable {
|
||||
|
||||
BuiltinVariable() {
|
||||
this instanceof GlobalVariable and
|
||||
not exists(this.(Variable).getAStore()) and
|
||||
not this.(Variable).getId() = "__name__" and
|
||||
not this.(Variable).getId() = "__package__" and
|
||||
not exists(ImportStar is | is.getScope() = this.(Variable).getScope())
|
||||
}
|
||||
|
||||
override ControlFlowNode getAnImplicitUse() {
|
||||
none()
|
||||
}
|
||||
|
||||
override ControlFlowNode getScopeEntryDefinition() {
|
||||
none()
|
||||
}
|
||||
|
||||
override CallNode redefinedAtCallSite() { none() }
|
||||
|
||||
}
|
||||
|
||||
class ModuleVariable extends PythonSsaSourceVariable {
|
||||
|
||||
ModuleVariable() {
|
||||
this instanceof GlobalVariable and
|
||||
(
|
||||
exists(this.(Variable).getAStore())
|
||||
or
|
||||
this.(Variable).getId() = "__name__"
|
||||
or
|
||||
this.(Variable).getId() = "__package__"
|
||||
or
|
||||
exists(ImportStar is | is.getScope() = this.(Variable).getScope())
|
||||
)
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
CallNode global_variable_callnode() {
|
||||
result.getScope() = this.(GlobalVariable).getScope()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
ImportMemberNode global_variable_import() {
|
||||
result.getScope() = this.(GlobalVariable).getScope() and
|
||||
import_from_dot_in_init(result.(ImportMemberNode).getModule(this.getName()))
|
||||
}
|
||||
|
||||
override ControlFlowNode getAnImplicitUse() {
|
||||
result = global_variable_callnode()
|
||||
or
|
||||
result = global_variable_import()
|
||||
or
|
||||
exists(ImportTimeScope scope |
|
||||
scope.entryEdge(result, _) |
|
||||
this = scope.getOuterVariable(_) or
|
||||
this.(Variable).getAUse().getScope() = scope
|
||||
)
|
||||
or
|
||||
/* For implicit use of __metaclass__ when constructing class */
|
||||
exists(Class c |
|
||||
class_with_global_metaclass(c, this) and
|
||||
c.(ImportTimeScope).entryEdge(result, _)
|
||||
)
|
||||
or
|
||||
exists(ImportTimeScope s |
|
||||
result = s.getANormalExit() and this.(Variable).getScope() = s and
|
||||
implicit_definition(this)
|
||||
)
|
||||
}
|
||||
|
||||
override ControlFlowNode getScopeEntryDefinition() {
|
||||
exists(Scope s |
|
||||
s.getEntryNode() = result |
|
||||
/* Module entry point */
|
||||
this.(GlobalVariable).getScope() = s
|
||||
or
|
||||
/* For implicit use of __metaclass__ when constructing class */
|
||||
class_with_global_metaclass(s, this)
|
||||
or
|
||||
/* Variable is used in scope */
|
||||
this.(GlobalVariable).getAUse().getScope() = s
|
||||
)
|
||||
or
|
||||
exists(ImportTimeScope scope |
|
||||
scope.entryEdge(_, result) |
|
||||
this = scope.getOuterVariable(_) or
|
||||
this.(Variable).getAUse().getScope() = scope
|
||||
)
|
||||
}
|
||||
|
||||
override CallNode redefinedAtCallSite() { none() }
|
||||
|
||||
}
|
||||
|
||||
class NonEscapingGlobalVariable extends ModuleVariable {
|
||||
|
||||
NonEscapingGlobalVariable() {
|
||||
this instanceof GlobalVariable and
|
||||
exists(this.(Variable).getAStore()) and
|
||||
not variable_or_attribute_defined_out_of_scope(this)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class EscapingGlobalVariable extends ModuleVariable {
|
||||
|
||||
EscapingGlobalVariable() {
|
||||
this instanceof GlobalVariable and exists(this.(Variable).getAStore()) and variable_or_attribute_defined_out_of_scope(this)
|
||||
}
|
||||
|
||||
override ControlFlowNode getAnImplicitUse() {
|
||||
result = ModuleVariable.super.getAnImplicitUse()
|
||||
or
|
||||
result.(CallNode).getScope().getScope+() = this.(GlobalVariable).getScope()
|
||||
or
|
||||
result = this.innerScope().getANormalExit()
|
||||
}
|
||||
|
||||
private Scope innerScope() {
|
||||
result.getScope+() = this.(GlobalVariable).getScope() and
|
||||
not result instanceof ImportTimeScope
|
||||
}
|
||||
|
||||
override ControlFlowNode getScopeEntryDefinition() {
|
||||
result = ModuleVariable.super.getScopeEntryDefinition()
|
||||
or
|
||||
result = this.innerScope().getEntryNode()
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
Scope scope_as_global_variable() {
|
||||
result = this.(GlobalVariable).getScope()
|
||||
}
|
||||
|
||||
override CallNode redefinedAtCallSite() {
|
||||
result.(CallNode).getScope().getScope*() = this.scope_as_global_variable()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class EscapingAssignmentGlobalVariable extends EscapingGlobalVariable {
|
||||
|
||||
EscapingAssignmentGlobalVariable() {
|
||||
exists(NameNode n | n.defines(this) and not n.getScope() = this.getScope())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class SpecialSsaSourceVariable extends PythonSsaSourceVariable {
|
||||
|
||||
SpecialSsaSourceVariable() {
|
||||
variable(this, _, "*") or variable(this, _, "$")
|
||||
}
|
||||
|
||||
override ControlFlowNode getAnImplicitUse() {
|
||||
exists(ImportTimeScope s |
|
||||
result = s.getANormalExit() and this.getScope() = s
|
||||
)
|
||||
}
|
||||
|
||||
override ControlFlowNode getScopeEntryDefinition() {
|
||||
/* Module entry point */
|
||||
this.getScope().getEntryNode() = result
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
Scope scope_as_global_variable() {
|
||||
result = this.(GlobalVariable).getScope()
|
||||
}
|
||||
|
||||
override CallNode redefinedAtCallSite() {
|
||||
result.(CallNode).getScope().getScope*() = this.scope_as_global_variable()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private predicate variable_or_attribute_defined_out_of_scope(Variable v) {
|
||||
exists(NameNode n | n.defines(v) and not n.getScope() = v.getScope())
|
||||
or
|
||||
exists(AttrNode a | a.isStore() and a.getObject() = v.getAUse() and not a.getScope() = v.getScope())
|
||||
}
|
||||
|
||||
private predicate class_with_global_metaclass(Class cls, GlobalVariable metaclass) {
|
||||
metaclass.getId() = "__metaclass__" and major_version() = 2 and
|
||||
cls.getEnclosingModule() = metaclass.getScope()
|
||||
}
|
||||
|
||||
|
||||
/** Holds if this variable is implicitly defined */
|
||||
private predicate implicit_definition(Variable v) {
|
||||
v.getId() = "*" or v.getId() = "$"
|
||||
or
|
||||
exists(ImportStar is | is.getScope() = v.getScope())
|
||||
}
|
||||
|
||||
cached module SsaSource {
|
||||
|
||||
@@ -435,7 +71,7 @@ cached module SsaSource {
|
||||
/** Holds if the name of `var` refers to a submodule of a package and `f` is the entry point
|
||||
* to the __init__ module of that package.
|
||||
*/
|
||||
cached predicate init_module_submodule_defn(PythonSsaSourceVariable var, ControlFlowNode f) {
|
||||
cached predicate init_module_submodule_defn(SsaSourceVariable var, ControlFlowNode f) {
|
||||
var instanceof GlobalVariable and
|
||||
exists(Module init |
|
||||
init.isPackageInit() and exists(init.getPackage().getSubModule(var.getName())) and
|
||||
@@ -445,7 +81,7 @@ cached module SsaSource {
|
||||
}
|
||||
|
||||
/** Holds if the `v` is in scope at a `from import ... *` and may thus be redefined by that statement */
|
||||
cached predicate import_star_refinement(PythonSsaSourceVariable v, ControlFlowNode use, ControlFlowNode def) {
|
||||
cached predicate import_star_refinement(SsaSourceVariable v, ControlFlowNode use, ControlFlowNode def) {
|
||||
use = def and def instanceof ImportStarNode
|
||||
and
|
||||
(
|
||||
@@ -491,19 +127,3 @@ cached module SsaSource {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private predicate refinement(PythonSsaSourceVariable v, ControlFlowNode use, ControlFlowNode def) {
|
||||
SsaSource::import_star_refinement(v, use, def)
|
||||
or
|
||||
SsaSource::attribute_assignment_refinement(v, use, def)
|
||||
or
|
||||
SsaSource::argument_refinement(v, use, def)
|
||||
or
|
||||
SsaSource::attribute_deletion_refinement(v, use, def)
|
||||
or
|
||||
SsaSource::test_refinement(v, use, def)
|
||||
or
|
||||
SsaSource::method_call_refinement(v, use, def)
|
||||
or
|
||||
def = v.redefinedAtCallSite() and def = use
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user