Python ESSA: Move definition sub-classes from points-to folder to essa folder.

This commit is contained in:
Mark Shannon
2019-08-20 11:17:18 +01:00
parent e34ccae1fc
commit 2ab3bf46cf
2 changed files with 330 additions and 325 deletions

View File

@@ -590,3 +590,333 @@ private EssaVariable potential_input(EssaNodeRefinement ref) {
var = ref.getSourceVariable()
)
}
/** Python specific sub-class of generic EssaNodeDefinition */
class PyNodeDefinition extends EssaNodeDefinition {
override string getRepresentation() {
result = this.getAQlClass()
}
}
/** Python specific sub-class of generic EssaNodeRefinement */
class PyNodeRefinement extends EssaNodeRefinement {
override string getRepresentation() {
result = this.getAQlClass() + "(" + this.getInput().getRepresentation() + ")"
or
not exists(this.getInput()) and
result = this.getAQlClass() + "(" + this.getSourceVariable().getName() + "??)"
}
}
/** An assignment to a variable `v = val` */
class AssignmentDefinition extends PyNodeDefinition {
AssignmentDefinition() {
SsaSource::assignment_definition(this.getSourceVariable(), this.getDefiningNode(), _)
}
ControlFlowNode getValue() {
SsaSource::assignment_definition(this.getSourceVariable(), this.getDefiningNode(), result)
}
override string getRepresentation() {
result = this.getValue().getNode().toString()
}
}
/** Capture of a raised exception `except ExceptionType ex:` */
class ExceptionCapture extends PyNodeDefinition {
ExceptionCapture() {
SsaSource::exception_capture(this.getSourceVariable(), this.getDefiningNode())
}
ControlFlowNode getType() {
exists(ExceptFlowNode ex |
ex.getName() = this.getDefiningNode() and
result = ex.getType()
)
}
override string getRepresentation() {
result = "except " + this.getSourceVariable().getName()
}
}
/** An assignment to a variable as part of a multiple assignment `..., v, ... = val` */
class MultiAssignmentDefinition extends PyNodeDefinition {
MultiAssignmentDefinition() {
SsaSource::multi_assignment_definition(this.getSourceVariable(), this.getDefiningNode(), _, _)
}
override string getRepresentation() {
exists(ControlFlowNode value, int n |
this.indexOf(n, value) and
result = value.(DefinitionNode).getValue().getNode().toString() + "[" + n + "]"
)
}
predicate indexOf(int index, SequenceNode lhs) {
SsaSource::multi_assignment_definition(this.getSourceVariable(), this.getDefiningNode(), index, lhs)
}
}
/** A definition of a variable in a `with` statement */
class WithDefinition extends PyNodeDefinition {
WithDefinition () {
SsaSource::with_definition(this.getSourceVariable(), this.getDefiningNode())
}
override string getRepresentation() {
result = "with"
}
}
/** A definition of a variable by declaring it as a parameter */
class ParameterDefinition extends PyNodeDefinition {
ParameterDefinition() {
SsaSource::parameter_definition(this.getSourceVariable(), this.getDefiningNode())
}
predicate isSelf() {
this.getDefiningNode().getNode().(Parameter).isSelf()
}
/** Gets the control flow node for the default value of this parameter */
ControlFlowNode getDefault() {
result.getNode() = this.getParameter().getDefault()
}
/** Gets the annotation control flow node of this parameter */
ControlFlowNode getAnnotation() {
result.getNode() = this.getParameter().getAnnotation()
}
/** Gets the name of this parameter definition */
string getName() {
result = this.getParameter().asName().getId()
}
predicate isVarargs() {
exists(Function func | func.getVararg() = this.getDefiningNode().getNode())
}
/** Holds if this parameter is a 'kwargs' parameter.
* The `kwargs` in `f(a, b, **kwargs)`.
*/
predicate isKwargs() {
exists(Function func | func.getKwarg() = this.getDefiningNode().getNode())
}
Parameter getParameter() {
result = this.getDefiningNode().getNode()
}
}
/** A deletion of a variable `del v` */
class DeletionDefinition extends PyNodeDefinition {
DeletionDefinition() {
SsaSource::deletion_definition(this.getSourceVariable(), this.getDefiningNode())
}
}
/** Definition of variable at the entry of a scope. Usually this represents the transfer of
* a global or non-local variable from one scope to another.
*/
class ScopeEntryDefinition extends PyNodeDefinition {
ScopeEntryDefinition() {
this.getDefiningNode() = this.getSourceVariable().(PythonSsaSourceVariable).getScopeEntryDefinition() and
not this instanceof ImplicitSubModuleDefinition
}
override Scope getScope() {
result.getEntryNode() = this.getDefiningNode()
}
}
/** Possible redefinition of variable via `from ... import *` */
class ImportStarRefinement extends PyNodeRefinement {
ImportStarRefinement() {
SsaSource::import_star_refinement(this.getSourceVariable(), _, this.getDefiningNode())
}
}
/** Assignment of an attribute `obj.attr = val` */
class AttributeAssignment extends PyNodeRefinement {
AttributeAssignment() {
SsaSource::attribute_assignment_refinement(this.getSourceVariable(), _, this.getDefiningNode())
}
string getName() {
result = this.getDefiningNode().(AttrNode).getName()
}
ControlFlowNode getValue() {
result = this.getDefiningNode().(DefinitionNode).getValue()
}
override string getRepresentation() {
result = this.getAQlClass() + " '" + this.getName() + "'(" + this.getInput().getRepresentation() + ")"
or
not exists(this.getInput()) and
result = this.getAQlClass() + " '" + this.getName() + "'(" + this.getSourceVariable().getName() + "??)"
}
}
/** A use of a variable as an argument, `foo(v)`, which might modify the object referred to. */
class ArgumentRefinement extends PyNodeRefinement {
ControlFlowNode argument;
ArgumentRefinement() {
SsaSource::argument_refinement(this.getSourceVariable(), argument, this.getDefiningNode())
}
ControlFlowNode getArgument() { result = argument }
CallNode getCall() { result = this.getDefiningNode() }
}
/** Deletion of an attribute `del obj.attr`. */
class EssaAttributeDeletion extends PyNodeRefinement {
EssaAttributeDeletion() {
SsaSource::attribute_deletion_refinement(this.getSourceVariable(), _, this.getDefiningNode())
}
string getName() {
result = this.getDefiningNode().(AttrNode).getName()
}
}
/** A pi-node (guard) with only one successor. */
class SingleSuccessorGuard extends PyNodeRefinement {
SingleSuccessorGuard() {
SsaSource::test_refinement(this.getSourceVariable(), _, this.getDefiningNode())
}
boolean getSense() {
exists(this.getDefiningNode().getAFalseSuccessor()) and result = false
or
exists(this.getDefiningNode().getATrueSuccessor()) and result = true
}
override string getRepresentation() {
result = PyNodeRefinement.super.getRepresentation() + " [" + this.getSense().toString() + "]"
or
not exists(this.getSense()) and
result = PyNodeRefinement.super.getRepresentation() + " [??]"
}
ControlFlowNode getTest() {
result = this.getDefiningNode()
}
predicate useAndTest(ControlFlowNode use, ControlFlowNode test) {
test = this.getDefiningNode() and
SsaSource::test_refinement(this.getSourceVariable(), use, test)
}
}
/** Implicit definition of the names of sub-modules in a package.
* Although the interpreter does not pre-define these names, merely populating them
* as they are imported, this is a good approximation for static analysis.
*/
class ImplicitSubModuleDefinition extends PyNodeDefinition {
ImplicitSubModuleDefinition() {
SsaSource::init_module_submodule_defn(this.getSourceVariable(), this.getDefiningNode())
}
}
/** An implicit (possible) definition of an escaping variable at a call-site */
class CallsiteRefinement extends PyNodeRefinement {
override string toString() {
result = "CallsiteRefinement"
}
CallsiteRefinement() {
exists(PythonSsaSourceVariable var, ControlFlowNode defn |
defn = var.redefinedAtCallSite() and
this.definedBy(var, defn) and
not this instanceof ArgumentRefinement and
not this instanceof MethodCallsiteRefinement and
not this instanceof SingleSuccessorGuard
)
}
CallNode getCall() {
this.getDefiningNode() = result
}
}
/** An implicit (possible) modification of the object referred at a method call */
class MethodCallsiteRefinement extends PyNodeRefinement {
MethodCallsiteRefinement() {
SsaSource::method_call_refinement(this.getSourceVariable(), _, this.getDefiningNode())
and not this instanceof SingleSuccessorGuard
}
CallNode getCall() {
this.getDefiningNode() = result
}
}
/** An implicit (possible) modification of `self` at a method call */
class SelfCallsiteRefinement extends MethodCallsiteRefinement {
SelfCallsiteRefinement() {
this.getSourceVariable().(Variable).isSelf()
}
}
/** Python specific sub-class of generic EssaEdgeRefinement */
class PyEdgeRefinement extends EssaEdgeRefinement {
override string getRepresentation() {
/* This is for testing so use capital 'P' to make it sort before 'phi' and
* be more visually distinctive. */
result = "Pi(" + this.getInput().getRepresentation() + ") [" + this.getSense() + "]"
or
not exists(this.getInput()) and
result = "Pi(" + this.getSourceVariable().getName() + "??) [" + this.getSense() + "]"
}
ControlFlowNode getTest() {
result = this.getPredecessor().getLastNode()
}
}

View File

@@ -174,139 +174,6 @@ predicate function_can_never_return(FunctionObject func) {
func = ModuleObject::named("sys").attr("exit")
}
/** Python specific sub-class of generic EssaNodeDefinition */
class PyNodeDefinition extends EssaNodeDefinition {
override string getRepresentation() {
result = this.getAQlClass()
}
}
/** Python specific sub-class of generic EssaNodeRefinement */
class PyNodeRefinement extends EssaNodeRefinement {
override string getRepresentation() {
result = this.getAQlClass() + "(" + this.getInput().getRepresentation() + ")"
or
not exists(this.getInput()) and
result = this.getAQlClass() + "(" + this.getSourceVariable().getName() + "??)"
}
}
/** An assignment to a variable `v = val` */
class AssignmentDefinition extends PyNodeDefinition {
AssignmentDefinition() {
SsaSource::assignment_definition(this.getSourceVariable(), this.getDefiningNode(), _)
}
ControlFlowNode getValue() {
SsaSource::assignment_definition(this.getSourceVariable(), this.getDefiningNode(), result)
}
override string getRepresentation() {
result = this.getValue().getNode().toString()
}
}
/** Capture of a raised exception `except ExceptionType ex:` */
class ExceptionCapture extends PyNodeDefinition {
ExceptionCapture() {
SsaSource::exception_capture(this.getSourceVariable(), this.getDefiningNode())
}
ControlFlowNode getType() {
exists(ExceptFlowNode ex |
ex.getName() = this.getDefiningNode() and
result = ex.getType()
)
}
override string getRepresentation() {
result = "except " + this.getSourceVariable().getName()
}
}
/** An assignment to a variable as part of a multiple assignment `..., v, ... = val` */
class MultiAssignmentDefinition extends PyNodeDefinition {
MultiAssignmentDefinition() {
SsaSource::multi_assignment_definition(this.getSourceVariable(), this.getDefiningNode(), _, _)
}
override string getRepresentation() {
exists(ControlFlowNode value, int n |
this.indexOf(n, value) and
result = value.(DefinitionNode).getValue().getNode().toString() + "[" + n + "]"
)
}
predicate indexOf(int index, SequenceNode lhs) {
SsaSource::multi_assignment_definition(this.getSourceVariable(), this.getDefiningNode(), index, lhs)
}
}
class WithDefinition extends PyNodeDefinition {
WithDefinition () {
SsaSource::with_definition(this.getSourceVariable(), this.getDefiningNode())
}
override string getRepresentation() {
result = "with"
}
}
/** A definition of a variable by declaring it as a parameter */
class ParameterDefinition extends PyNodeDefinition {
ParameterDefinition() {
SsaSource::parameter_definition(this.getSourceVariable(), this.getDefiningNode())
}
predicate isSelf() {
this.getDefiningNode().getNode().(Parameter).isSelf()
}
/** Gets the control flow node for the default value of this parameter */
ControlFlowNode getDefault() {
result.getNode() = this.getParameter().getDefault()
}
/** Gets the annotation control flow node of this parameter */
ControlFlowNode getAnnotation() {
result.getNode() = this.getParameter().getAnnotation()
}
/** Gets the name of this parameter definition */
string getName() {
result = this.getParameter().asName().getId()
}
predicate isVarargs() {
exists(Function func | func.getVararg() = this.getDefiningNode().getNode())
}
/** Holds if this parameter is a 'kwargs' parameter.
* The `kwargs` in `f(a, b, **kwargs)`.
*/
predicate isKwargs() {
exists(Function func | func.getKwarg() = this.getDefiningNode().getNode())
}
Parameter getParameter() {
result = this.getDefiningNode().getNode()
}
}
private newtype TIterationDefinition =
TIterationDefinition_(SsaSourceVariable var, ControlFlowNode def, ControlFlowNode sequence) {
@@ -328,198 +195,6 @@ deprecated class IterationDefinition extends TIterationDefinition {
}
/** A deletion of a variable `del v` */
class DeletionDefinition extends PyNodeDefinition {
DeletionDefinition() {
SsaSource::deletion_definition(this.getSourceVariable(), this.getDefiningNode())
}
}
/** Definition of variable at the entry of a scope. Usually this represents the transfer of
* a global or non-local variable from one scope to another.
*/
class ScopeEntryDefinition extends PyNodeDefinition {
ScopeEntryDefinition() {
this.getDefiningNode() = this.getSourceVariable().(PythonSsaSourceVariable).getScopeEntryDefinition() and
not this instanceof ImplicitSubModuleDefinition
}
override Scope getScope() {
result.getEntryNode() = this.getDefiningNode()
}
}
/** Possible redefinition of variable via `from ... import *` */
class ImportStarRefinement extends PyNodeRefinement {
ImportStarRefinement() {
SsaSource::import_star_refinement(this.getSourceVariable(), _, this.getDefiningNode())
}
}
/** Assignment of an attribute `obj.attr = val` */
class AttributeAssignment extends PyNodeRefinement {
AttributeAssignment() {
SsaSource::attribute_assignment_refinement(this.getSourceVariable(), _, this.getDefiningNode())
}
string getName() {
result = this.getDefiningNode().(AttrNode).getName()
}
ControlFlowNode getValue() {
result = this.getDefiningNode().(DefinitionNode).getValue()
}
override string getRepresentation() {
result = this.getAQlClass() + " '" + this.getName() + "'(" + this.getInput().getRepresentation() + ")"
or
not exists(this.getInput()) and
result = this.getAQlClass() + " '" + this.getName() + "'(" + this.getSourceVariable().getName() + "??)"
}
}
/** A use of a variable as an argument, `foo(v)`, which might modify the object referred to. */
class ArgumentRefinement extends PyNodeRefinement {
ControlFlowNode argument;
ArgumentRefinement() {
SsaSource::argument_refinement(this.getSourceVariable(), argument, this.getDefiningNode())
}
ControlFlowNode getArgument() { result = argument }
CallNode getCall() { result = this.getDefiningNode() }
}
/** Deletion of an attribute `del obj.attr`. */
class EssaAttributeDeletion extends PyNodeRefinement {
EssaAttributeDeletion() {
SsaSource::attribute_deletion_refinement(this.getSourceVariable(), _, this.getDefiningNode())
}
string getName() {
result = this.getDefiningNode().(AttrNode).getName()
}
}
/** A pi-node (guard) with only one successor. */
class SingleSuccessorGuard extends PyNodeRefinement {
SingleSuccessorGuard() {
SsaSource::test_refinement(this.getSourceVariable(), _, this.getDefiningNode())
}
boolean getSense() {
exists(this.getDefiningNode().getAFalseSuccessor()) and result = false
or
exists(this.getDefiningNode().getATrueSuccessor()) and result = true
}
override string getRepresentation() {
result = PyNodeRefinement.super.getRepresentation() + " [" + this.getSense().toString() + "]"
or
not exists(this.getSense()) and
result = PyNodeRefinement.super.getRepresentation() + " [??]"
}
ControlFlowNode getTest() {
result = this.getDefiningNode()
}
predicate useAndTest(ControlFlowNode use, ControlFlowNode test) {
test = this.getDefiningNode() and
SsaSource::test_refinement(this.getSourceVariable(), use, test)
}
}
/** Implicit definition of the names of sub-modules in a package.
* Although the interpreter does not pre-define these names, merely populating them
* as they are imported, this is a good approximation for static analysis.
*/
class ImplicitSubModuleDefinition extends PyNodeDefinition {
ImplicitSubModuleDefinition() {
SsaSource::init_module_submodule_defn(this.getSourceVariable(), this.getDefiningNode())
}
}
/** An implicit (possible) definition of an escaping variable at a call-site */
class CallsiteRefinement extends PyNodeRefinement {
override string toString() {
result = "CallsiteRefinement"
}
CallsiteRefinement() {
exists(PythonSsaSourceVariable var, ControlFlowNode defn |
defn = var.redefinedAtCallSite() and
this.definedBy(var, defn) and
not this instanceof ArgumentRefinement and
not this instanceof MethodCallsiteRefinement and
not this instanceof SingleSuccessorGuard
)
}
CallNode getCall() {
this.getDefiningNode() = result
}
}
/** An implicit (possible) modification of the object referred at a method call */
class MethodCallsiteRefinement extends PyNodeRefinement {
MethodCallsiteRefinement() {
SsaSource::method_call_refinement(this.getSourceVariable(), _, this.getDefiningNode())
and not this instanceof SingleSuccessorGuard
}
CallNode getCall() {
this.getDefiningNode() = result
}
}
/** An implicit (possible) modification of `self` at a method call */
class SelfCallsiteRefinement extends MethodCallsiteRefinement {
SelfCallsiteRefinement() {
this.getSourceVariable().(Variable).isSelf()
}
}
/** Python specific sub-class of generic EssaEdgeRefinement */
class PyEdgeRefinement extends EssaEdgeRefinement {
override string getRepresentation() {
/* This is for testing so use capital 'P' to make it sort before 'phi' and
* be more visually distinctive. */
result = "Pi(" + this.getInput().getRepresentation() + ") [" + this.getSense() + "]"
or
not exists(this.getInput()) and
result = "Pi(" + this.getSourceVariable().getName() + "??) [" + this.getSense() + "]"
}
ControlFlowNode getTest() {
result = this.getPredecessor().getLastNode()
}
}
/** Hold if outer contains inner, both are contained within a test and inner is a use is a plain use or an attribute lookup */
pragma[noinline]
predicate contains_interesting_expression_within_test(ControlFlowNode outer, ControlFlowNode inner) {