mirror of
https://github.com/github/codeql.git
synced 2026-01-08 12:10:22 +01:00
274 lines
8.6 KiB
Plaintext
274 lines
8.6 KiB
Plaintext
/**
|
|
* Provides Python-specific definitions for use in the data flow library.
|
|
*/
|
|
|
|
private import python
|
|
private import DataFlowPrivate
|
|
import experimental.dataflow.TypeTracker
|
|
|
|
/**
|
|
* IPA type for data flow nodes.
|
|
*
|
|
* Flow between SSA variables are computed in `Essa.qll`
|
|
*
|
|
* Flow from SSA variables to control flow nodes are generally via uses.
|
|
*
|
|
* Flow from control flow nodes to SSA variables are generally via assignments.
|
|
*
|
|
* The current implementation of these cross flows can be seen in `EssaTaintTracking`.
|
|
*/
|
|
newtype TNode =
|
|
/** A node corresponding to an SSA variable. */
|
|
TEssaNode(EssaVariable var) or
|
|
/** A node corresponding to a control flow node. */
|
|
TCfgNode(DataFlowCfgNode node) or
|
|
/** A node representing the value of an object after a state change */
|
|
TPostUpdateNode(PreUpdateNode pre) or
|
|
/** A node representing a global (module-level) variable in a specific module */
|
|
TModuleVariableNode(Module m, GlobalVariable v) { v.getScope() = m and v.escapes() }
|
|
|
|
/**
|
|
* An element, viewed as a node in a data flow graph. Either an SSA variable
|
|
* (`EssaNode`) or a control flow node (`CfgNode`).
|
|
*/
|
|
class Node extends TNode {
|
|
/** Gets a textual representation of this element. */
|
|
string toString() { result = "Data flow node" }
|
|
|
|
/** Gets the scope of this node. */
|
|
Scope getScope() { none() }
|
|
|
|
private DataFlowCallable getCallableScope(Scope s) {
|
|
result.getScope() = s
|
|
or
|
|
not exists(DataFlowCallable c | c.getScope() = s) and
|
|
result = getCallableScope(s.getEnclosingScope())
|
|
}
|
|
|
|
/** Gets the enclosing callable of this node. */
|
|
DataFlowCallable getEnclosingCallable() { result = getCallableScope(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`.
|
|
* For more information, see
|
|
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
|
*/
|
|
predicate hasLocationInfo(
|
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
|
}
|
|
|
|
/** Convenience method for casting to EssaNode and calling getVar. */
|
|
EssaVariable asVar() { none() }
|
|
|
|
/** Convenience method for casting to CfgNode and calling getNode. */
|
|
ControlFlowNode asCfgNode() { none() }
|
|
|
|
/** Convenience method for casting to ExprNode and calling getNode and getNode again. */
|
|
Expr asExpr() { none() }
|
|
|
|
/**
|
|
* Gets a node that this node may flow to using one heap and/or interprocedural step.
|
|
*
|
|
* See `TypeTracker` for more details about how to use this.
|
|
*/
|
|
pragma[inline]
|
|
Node track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) }
|
|
}
|
|
|
|
class EssaNode extends Node, TEssaNode {
|
|
EssaVariable var;
|
|
|
|
EssaNode() { this = TEssaNode(var) }
|
|
|
|
EssaVariable getVar() { result = var }
|
|
|
|
override EssaVariable asVar() { result = var }
|
|
|
|
/** Gets a textual representation of this element. */
|
|
override string toString() { result = var.toString() }
|
|
|
|
override Scope getScope() { result = var.getScope() }
|
|
|
|
override Location getLocation() { result = var.getDefinition().getLocation() }
|
|
}
|
|
|
|
class CfgNode extends Node, TCfgNode {
|
|
DataFlowCfgNode node;
|
|
|
|
CfgNode() { this = TCfgNode(node) }
|
|
|
|
ControlFlowNode getNode() { result = node }
|
|
|
|
override ControlFlowNode asCfgNode() { result = node }
|
|
|
|
/** Gets a textual representation of this element. */
|
|
override string toString() { result = node.toString() }
|
|
|
|
override Scope getScope() { result = node.getScope() }
|
|
|
|
override Location getLocation() { result = node.getLocation() }
|
|
}
|
|
|
|
/**
|
|
* An expression, viewed as a node in a data flow graph.
|
|
*
|
|
* Note that because of control-flow splitting, one `Expr` may correspond
|
|
* to multiple `ExprNode`s, just like it may correspond to multiple
|
|
* `ControlFlow::Node`s.
|
|
*/
|
|
class ExprNode extends CfgNode {
|
|
ExprNode() { isExpressionNode(node) }
|
|
|
|
override Expr asExpr() { result = node.getNode() }
|
|
}
|
|
|
|
/** Gets a node corresponding to expression `e`. */
|
|
ExprNode exprNode(DataFlowExpr e) { result.getNode().getNode() = e }
|
|
|
|
/**
|
|
* The value of a parameter at function entry, viewed as a node in a data
|
|
* flow graph.
|
|
*/
|
|
class ParameterNode extends EssaNode {
|
|
ParameterNode() { var instanceof ParameterDefinition }
|
|
|
|
/**
|
|
* Holds if this node is the parameter of callable `c` at the
|
|
* (zero-based) index `i`.
|
|
*/
|
|
predicate isParameterOf(DataFlowCallable c, int i) {
|
|
var.(ParameterDefinition).getDefiningNode() = c.getParameter(i)
|
|
}
|
|
|
|
override DataFlowCallable getEnclosingCallable() { this.isParameterOf(result, _) }
|
|
}
|
|
|
|
class ModuleVariableNode extends Node, TModuleVariableNode {
|
|
Module mod;
|
|
GlobalVariable var;
|
|
|
|
ModuleVariableNode() { this = TModuleVariableNode(mod, var) }
|
|
|
|
override Scope getScope() { result = mod }
|
|
|
|
override string toString() {
|
|
result = "ModuleVariableNode for " + var.toString() + " in " + mod.toString()
|
|
}
|
|
|
|
/** Gets the module in which this variable appears. */
|
|
Module getModule() { result = mod }
|
|
|
|
/** Gets the global variable corresponding to this node. */
|
|
GlobalVariable getVariable() { result = var }
|
|
|
|
/** Gets a node that reads this variable. */
|
|
Node getARead() {
|
|
result.asCfgNode() = var.getALoad().getAFlowNode() and
|
|
// Ignore reads that happen when the module is imported. These are only executed once.
|
|
not result.getScope() = mod
|
|
}
|
|
|
|
/** Gets an `EssaNode` that corresponds to an assignment of this global variable. */
|
|
Node getAWrite() {
|
|
exists(DefinitionNode defn |
|
|
result.asVar().getDefinition().(EssaNodeDefinition).definedBy(var, defn)
|
|
)
|
|
}
|
|
|
|
override DataFlowCallable getEnclosingCallable() { result.(DataFlowModuleScope).getScope() = mod }
|
|
|
|
override Location getLocation() { result = mod.getLocation() }
|
|
}
|
|
|
|
/**
|
|
* A guard that validates some expression.
|
|
*
|
|
* To use this in a configuration, extend the class and provide a
|
|
* characteristic predicate precisely specifying the guard, and override
|
|
* `checks` to specify what is being validated and in which branch.
|
|
*
|
|
* It is important that all extending classes in scope are disjoint.
|
|
*/
|
|
class BarrierGuard extends Expr {
|
|
// /** Holds if this guard validates `e` upon evaluating to `v`. */
|
|
// abstract predicate checks(Expr e, AbstractValue v);
|
|
/** Gets a node guarded by this guard. */
|
|
final ExprNode getAGuardedNode() {
|
|
none()
|
|
// exists(Expr e, AbstractValue v |
|
|
// this.checks(e, v) and
|
|
// this.controlsNode(result.getControlFlowNode(), e, v)
|
|
// )
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A reference contained in an object. This is either a field or a property.
|
|
*/
|
|
newtype TContent =
|
|
/** An element of a list. */
|
|
TListElementContent() or
|
|
/** An element of a set. */
|
|
TSetElementContent() or
|
|
/** An element of a tuple at a specifik index. */
|
|
TTupleElementContent(int index) { exists(any(TupleNode tn).getElement(index)) } or
|
|
/** An element of a dictionary under a specific key. */
|
|
TDictionaryElementContent(string key) {
|
|
key = any(KeyValuePair kvp).getKey().(StrConst).getS()
|
|
or
|
|
key = any(Keyword kw).getArg()
|
|
} or
|
|
/** An element of a dictionary at any key. */
|
|
TDictionaryElementAnyContent()
|
|
|
|
class Content extends TContent {
|
|
/** Gets a textual representation of this element. */
|
|
string toString() { result = "Content" }
|
|
}
|
|
|
|
class ListElementContent extends TListElementContent, Content {
|
|
/** Gets a textual representation of this element. */
|
|
override string toString() { result = "List element" }
|
|
}
|
|
|
|
class SetElementContent extends TSetElementContent, Content {
|
|
/** Gets a textual representation of this element. */
|
|
override string toString() { result = "Set element" }
|
|
}
|
|
|
|
class TupleElementContent extends TTupleElementContent, Content {
|
|
int index;
|
|
|
|
TupleElementContent() { this = TTupleElementContent(index) }
|
|
|
|
/** Gets the index for this tuple element */
|
|
int getIndex() { result = index }
|
|
|
|
/** Gets a textual representation of this element. */
|
|
override string toString() { result = "Tuple element at index " + index.toString() }
|
|
}
|
|
|
|
class DictionaryElementContent extends TDictionaryElementContent, Content {
|
|
string key;
|
|
|
|
DictionaryElementContent() { this = TDictionaryElementContent(key) }
|
|
|
|
/** Gets the index for this tuple element */
|
|
string getKey() { result = key }
|
|
|
|
/** Gets a textual representation of this element. */
|
|
override string toString() { result = "Dictionary element at key " + key }
|
|
}
|
|
|
|
class DictionaryElementAnyContent extends TDictionaryElementAnyContent, Content {
|
|
/** Gets a textual representation of this element. */
|
|
override string toString() { result = "Any dictionary element" }
|
|
}
|