Python: refactor Node class

This commit is contained in:
Rasmus Lerchedahl Petersen
2020-07-03 08:01:44 +02:00
parent 5f18fb427a
commit bdc68ce6b6
5 changed files with 92 additions and 106 deletions

View File

@@ -40,15 +40,15 @@ module EssaFlow {
// `x = f(42)`
// nodeFrom is `f(42)`, cfg node
// nodeTo is `x`, essa var
nodeFrom.asCfgNode() = nodeTo.asEssaNode().getDefinition().(AssignmentDefinition).getValue()
nodeFrom.(CfgNode).getNode() = nodeTo.(EssaNode).getVar().getDefinition().(AssignmentDefinition).getValue()
or
// With definition
// `with f(42) as x:`
// nodeFrom is `f(42)`, cfg node
// nodeTo is `x`, essa var
exists(With with, ControlFlowNode contextManager, ControlFlowNode var |
nodeFrom.asCfgNode() = contextManager and
nodeTo.asEssaNode().getDefinition().(WithDefinition).getDefiningNode() = var and
nodeFrom.(CfgNode).getNode() = contextManager and
nodeTo.(EssaNode).getVar().getDefinition().(WithDefinition).getDefiningNode() = var and
// see `with_flow`
with.getContextExpr() = contextManager.getNode() and
with.getOptionalVars() = var.getNode() and
@@ -60,22 +60,22 @@ module EssaFlow {
// `x = f(y)`
// nodeFrom is `y` on first line, essa var
// nodeTo is `y` on second line, cfg node
nodeFrom.asEssaNode().getAUse() = nodeTo.asCfgNode()
nodeFrom.(EssaNode).getVar().getAUse() = nodeTo.(CfgNode).getNode()
or
// Refinements
exists(EssaEdgeRefinement r |
nodeTo.asEssaNode() = r.getVariable() and
nodeFrom.asEssaNode() = r.getInput()
nodeTo.(EssaNode).getVar() = r.getVariable() and
nodeFrom.(EssaNode).getVar() = r.getInput()
)
or
exists(EssaNodeRefinement r |
nodeTo.asEssaNode() = r.getVariable() and
nodeFrom.asEssaNode() = r.getInput()
nodeTo.(EssaNode).getVar() = r.getVariable() and
nodeFrom.(EssaNode).getVar() = r.getInput()
)
or
exists(PhiFunction p |
nodeTo.asEssaNode() = p.getVariable() and
nodeFrom.asEssaNode() = p.getAnInput()
nodeTo.(EssaNode).getVar() = p.getVariable() and
nodeFrom.(EssaNode).getVar() = p.getAnInput()
)
}
}
@@ -119,19 +119,19 @@ class DataFlowCall extends CallNode {
}
/** A data flow node that represents a call argument. */
class ArgumentNode extends Node {
class ArgumentNode extends CfgNode {
ArgumentNode() {
exists(DataFlowCall call, int pos |
this.asCfgNode() = call.getArg(pos)
node = call.getArg(pos)
)
}
/** Holds if this argument occurs at the given position in the given call. */
/** Holds if this argument occurs at the given position in the given call. */
predicate argumentOf(DataFlowCall call, int pos) {
this.asCfgNode() = call.getArg(pos)
node = call.getArg(pos)
}
/** Gets the call in which this node is an argument. */
/** Gets the call in which this node is an argument. */
final DataFlowCall getCall() { this.argumentOf(result, _) }
}
@@ -152,31 +152,31 @@ class ReturnKind extends TReturnKind {
}
/** A data flow node that represents a value returned by a callable. */
class ReturnNode extends Node {
class ReturnNode extends CfgNode {
Return ret;
// See `TaintTrackingImplementation::returnFlowStep`
// See `TaintTrackingImplementation::returnFlowStep`
ReturnNode() {
this.asCfgNode() = ret.getValue().getAFlowNode()
node = ret.getValue().getAFlowNode()
}
/** Gets the kind of this return node. */
/** Gets the kind of this return node. */
ReturnKind getKind() { result = TNormalReturnKind() }
override DataFlowCallable getEnclosingCallable() {
override DataFlowCallable getEnclosingCallable() {
result.getScope().getAStmt() = ret // TODO: check nested function definitions
}
}
/** A data flow node that represents the output of a call. */
class OutNode extends Node {
OutNode() { this.asCfgNode() instanceof CallNode }
class OutNode extends CfgNode {
OutNode() { node instanceof CallNode }
/** Gets the underlying call, where this node is a corresponding output of kind `kind`. */
/** Gets the underlying call, where this node is a corresponding output of kind `kind`. */
cached
DataFlowCall getCall(ReturnKind kind) {
kind = TNormalReturnKind() and
result = this.asCfgNode()
result = node
}
}
@@ -231,13 +231,13 @@ string ppReprType(DataFlowType t) { result = t.toString() }
* another. Additional steps specified by the configuration are *not*
* taken into account.
*/
predicate jumpStep(ExprNode pred, ExprNode succ) {
predicate jumpStep(Node pred, Node succ) {
// As we have ESSA variables for global variables,
// we include ESSA flow steps involving global variables.
(
pred.asEssaNode() instanceof GlobalSsaVariable
pred.(EssaNode).getVar() instanceof GlobalSsaVariable
or
succ.asEssaNode() instanceof GlobalSsaVariable
succ.(EssaNode).getVar() instanceof GlobalSsaVariable
) and
EssaFlow::essaFlowStep(pred, succ)
}

View File

@@ -27,34 +27,23 @@ newtype TNode =
* (`ExprNode`) or a parameter (`ParameterNode`).
*/
class Node extends TNode {
/**
* Get the underlying SSA variable if this is such a node.
*/
EssaVariable asEssaNode() { this = TEssaNode(result) }
/**
* Get the underlying ControlFlowNode if this is such a node.
*/
ControlFlowNode asCfgNode() { this = TCfgNode(result) }
/**
* Get a string representation of this data flow node.
*/
string toString() {
result = this.asEssaNode().toString()
or
result = this.asCfgNode().toString()
}
string toString() { result = "Data flow node" }
/** Gets the enclosing callable of this node. */
/** Gets the scope of this node. */
Scope getScope() { none() }
/** Gets the enclosing callable of this node. */
DataFlowCallable getEnclosingCallable() {
result.getScope() = this.asCfgNode().getNode().getScope() // this allows Cfg -> ESSA def
or
result.getScope() = this.asEssaNode().getScope() // this allows ESSA var -> Cfg use
result.getScope() = this.getScope()
}
/**
/** Gets the location of this node */
Location getLocation() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
@@ -64,12 +53,47 @@ class Node extends TNode {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.asEssaNode().getDefinition().getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
or
this.asCfgNode().getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
this.getLocation()
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
class EssaNode extends Node, TEssaNode {
EssaVariable var;
EssaNode() { this = TEssaNode(var) }
EssaVariable getVar() { result = var }
/**
* Get a string representation of this data flow node.
*/
override string toString() {
result = var.toString()
}
override Scope getScope() { result = var.getScope() }
override Location getLocation() { result = var.getDefinition().getLocation() }
}
class CfgNode extends Node, TCfgNode {
ControlFlowNode node;
CfgNode() { this = TCfgNode(node) }
ControlFlowNode getNode() { result = node }
/**
* Get a string representation of this data flow node.
*/
override string toString() {
result = node.toString()
}
override Scope getScope() { result = node.getScope() }
override Location getLocation() { result = node.getLocation() }
}
/**
@@ -89,22 +113,18 @@ ExprNode exprNode(DataFlowExpr e) { none() }
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
class ParameterNode extends Node {
ParameterNode() {
this.asEssaNode() instanceof ParameterDefinition
}
class ParameterNode extends EssaNode {
ParameterNode() { var instanceof ParameterDefinition }
/**
/**
* Holds if this node is the parameter of callable `c` at the specified
* (zero-based) position.
*/
predicate isParameterOf(DataFlowCallable c, int i) {
this.asEssaNode().(ParameterDefinition).getDefiningNode() = c.getParameter(i)
var.(ParameterDefinition).getDefiningNode() = c.getParameter(i)
}
override DataFlowCallable getEnclosingCallable() {
this.isParameterOf(result, _)
}
override DataFlowCallable getEnclosingCallable() { this.isParameterOf(result, _) }
}
/**