Files
codeql/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll
Philip Ginsbach c9c0c7f24f fix formatting
2021-10-13 13:10:37 +01:00

253 lines
8.1 KiB
Plaintext

private import csharp
private import cil
private import dotnet
private import DataFlowDispatch
private import DataFlowPrivate
private import semmle.code.csharp.controlflow.Guards
private import semmle.code.csharp.Unification
/**
* An element, viewed as a node in a data flow graph. Either an expression
* (`ExprNode`) or a parameter (`ParameterNode`).
*/
class Node extends TNode {
/** Gets the expression corresponding to this node, if any. */
DotNet::Expr asExpr() { result = this.(ExprNode).getExpr() }
/**
* Gets the expression corresponding to this node, at control flow node `cfn`,
* if any.
*/
Expr asExprAtNode(ControlFlow::Nodes::ElementNode cfn) {
result = this.(ExprNode).getExprAtNode(cfn)
}
/** Gets the parameter corresponding to this node, if any. */
DotNet::Parameter asParameter() { result = this.(ParameterNode).getParameter() }
/** Gets the definition corresponding to this node, if any. */
AssignableDefinition asDefinition() { result = this.asDefinitionAtNode(_) }
/**
* Gets the definition corresponding to this node, at control flow node `cfn`,
* if any.
*/
AssignableDefinition asDefinitionAtNode(ControlFlow::Node cfn) {
result = this.(AssignableDefinitionNode).getDefinitionAtNode(cfn)
}
/** Gets the type of this node. */
final DotNet::Type getType() { result = this.(NodeImpl).getTypeImpl() }
/** Gets the enclosing callable of this node. */
final DataFlowCallable getEnclosingCallable() {
result = this.(NodeImpl).getEnclosingCallableImpl()
}
/** Gets the control flow node corresponding to this node, if any. */
final ControlFlow::Node getControlFlowNode() { result = this.(NodeImpl).getControlFlowNodeImpl() }
/** Gets a textual representation of this node. */
final string toString() { result = this.(NodeImpl).toStringImpl() }
/** Gets the location of this node. */
final Location getLocation() { result = this.(NodeImpl).getLocationImpl() }
/**
* 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://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
private class TExprNode_ = TExprNode or TCilExprNode;
/**
* 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 Node, TExprNode_ {
/** Gets the expression corresponding to this node. */
DotNet::Expr getExpr() {
result = this.getExprAtNode(_)
or
this = TCilExprNode(result)
}
/**
* Gets the expression corresponding to this node, at control flow node `cfn`,
* if any.
*/
Expr getExprAtNode(ControlFlow::Nodes::ElementNode cfn) {
this = TExprNode(cfn) and
result = cfn.getElement()
}
}
/**
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
class ParameterNode extends Node instanceof ParameterNodeImpl {
/** Gets the parameter corresponding to this node, if any. */
DotNet::Parameter getParameter() {
exists(DataFlowCallable c, int i | this.isParameterOf(c, i) and result = c.getParameter(i))
}
/**
* Holds if this node is the parameter of callable `c` at the specified
* (zero-based) position.
*/
predicate isParameterOf(DataFlowCallable c, int i) { super.isParameterOf(c, i) }
}
/** A definition, viewed as a node in a data flow graph. */
class AssignableDefinitionNode extends Node, TSsaDefinitionNode {
private Ssa::ExplicitDefinition edef;
AssignableDefinitionNode() { this = TSsaDefinitionNode(edef) }
/** Gets the underlying definition. */
AssignableDefinition getDefinition() { result = this.getDefinitionAtNode(_) }
/** Gets the underlying definition, at control flow node `cfn`, if any. */
AssignableDefinition getDefinitionAtNode(ControlFlow::Node cfn) {
result = edef.getADefinition() and
cfn = edef.getControlFlowNode()
}
}
/** Gets a node corresponding to expression `e`. */
ExprNode exprNode(DotNet::Expr e) { result.getExpr() = e }
/**
* Gets the node corresponding to the value of parameter `p` at function entry.
*/
ParameterNode parameterNode(DotNet::Parameter p) { result.getParameter() = p }
/** Gets a node corresponding to the definition `def`. */
AssignableDefinitionNode assignableDefinitionNode(AssignableDefinition def) {
result.getDefinition() = def
}
predicate localFlowStep = localFlowStepImpl/2;
/**
* Holds if data flows from `source` to `sink` in zero or more local
* (intra-procedural) steps.
*/
pragma[inline]
predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
/**
* Holds if data can flow from `e1` to `e2` in zero or more
* local (intra-procedural) steps.
*/
predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)) }
/**
* A data flow node that jumps between callables. This can be extended in
* framework code to add additional data flow steps.
*/
abstract class NonLocalJumpNode extends Node {
/** Gets a successor node that is potentially in another callable. */
abstract Node getAJumpSuccessor(boolean preservesValue);
}
/**
* 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 Guard {
/** 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() {
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, a property,
* or an element in a collection.
*/
class Content extends TContent {
/** Gets a textual representation of this content. */
string toString() { none() }
/** Gets the location of this content. */
Location getLocation() { none() }
/** Gets the type of the object containing this content. */
deprecated Gvn::GvnType getContainerType() { none() }
/** Gets the type of this content. */
deprecated Gvn::GvnType getType() { none() }
}
/** A reference to a field. */
class FieldContent extends Content, TFieldContent {
private Field f;
FieldContent() { this = TFieldContent(f) }
/** Gets the field that is referenced. */
Field getField() { result = f }
override string toString() { result = "field " + f.getName() }
override Location getLocation() { result = f.getLocation() }
deprecated override Gvn::GvnType getContainerType() {
result = Gvn::getGlobalValueNumber(f.getDeclaringType())
}
deprecated override Gvn::GvnType getType() { result = Gvn::getGlobalValueNumber(f.getType()) }
}
/** A reference to a property. */
class PropertyContent extends Content, TPropertyContent {
private Property p;
PropertyContent() { this = TPropertyContent(p) }
/** Gets the property that is referenced. */
Property getProperty() { result = p }
override string toString() { result = "property " + p.getName() }
override Location getLocation() { result = p.getLocation() }
deprecated override Gvn::GvnType getContainerType() {
result = Gvn::getGlobalValueNumber(p.getDeclaringType())
}
deprecated override Gvn::GvnType getType() { result = Gvn::getGlobalValueNumber(p.getType()) }
}
/** A reference to an element in a collection. */
class ElementContent extends Content, TElementContent {
override string toString() { result = "element" }
override Location getLocation() { result instanceof EmptyLocation }
}