mirror of
https://github.com/github/codeql.git
synced 2026-04-23 15:55:18 +02:00
Merge pull request #3652 from hvitved/csharp/dataflow/impl-layer
C#: Refactor data-flow predicates defined by dispatch
This commit is contained in:
@@ -16,6 +16,42 @@ private import semmle.code.csharp.dispatch.Dispatch
|
||||
private import semmle.code.csharp.frameworks.EntityFramework
|
||||
private import semmle.code.csharp.frameworks.NHibernate
|
||||
|
||||
abstract class NodeImpl extends Node {
|
||||
/** Do not call: use `getEnclosingCallable()` instead. */
|
||||
abstract DataFlowCallable getEnclosingCallableImpl();
|
||||
|
||||
/** Do not call: use `getType()` instead. */
|
||||
abstract DotNet::Type getTypeImpl();
|
||||
|
||||
/** Do not call: use `getControlFlowNode()` instead. */
|
||||
abstract ControlFlow::Node getControlFlowNodeImpl();
|
||||
|
||||
/** Do not call: use `getLocation()` instead. */
|
||||
abstract Location getLocationImpl();
|
||||
|
||||
/** Do not call: use `toString()` instead. */
|
||||
abstract string toStringImpl();
|
||||
}
|
||||
|
||||
private class ExprNodeImpl extends ExprNode, NodeImpl {
|
||||
override DataFlowCallable getEnclosingCallableImpl() {
|
||||
result = this.getExpr().getEnclosingCallable()
|
||||
}
|
||||
|
||||
override DotNet::Type getTypeImpl() { result = this.getExpr().getType() }
|
||||
|
||||
override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() { this = TExprNode(result) }
|
||||
|
||||
override Location getLocationImpl() { result = this.getExpr().getLocation() }
|
||||
|
||||
override string toStringImpl() {
|
||||
result = this.getControlFlowNode().toString()
|
||||
or
|
||||
this = TCilExprNode(_) and
|
||||
result = "CIL expression"
|
||||
}
|
||||
}
|
||||
|
||||
/** Calculation of the relative order in which `this` references are read. */
|
||||
private module ThisFlow {
|
||||
private class BasicBlock = ControlFlow::BasicBlock;
|
||||
@@ -553,7 +589,7 @@ private module Cached {
|
||||
import Cached
|
||||
|
||||
/** An SSA definition, viewed as a node in a data flow graph. */
|
||||
class SsaDefinitionNode extends Node, TSsaDefinitionNode {
|
||||
class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
|
||||
Ssa::Definition def;
|
||||
|
||||
SsaDefinitionNode() { this = TSsaDefinitionNode(def) }
|
||||
@@ -561,19 +597,23 @@ class SsaDefinitionNode extends Node, TSsaDefinitionNode {
|
||||
/** Gets the underlying SSA definition. */
|
||||
Ssa::Definition getDefinition() { result = def }
|
||||
|
||||
override Callable getEnclosingCallable() { result = def.getEnclosingCallable() }
|
||||
override Callable getEnclosingCallableImpl() { result = def.getEnclosingCallable() }
|
||||
|
||||
override Type getType() { result = def.getSourceVariable().getType() }
|
||||
override Type getTypeImpl() { result = def.getSourceVariable().getType() }
|
||||
|
||||
override Location getLocation() { result = def.getLocation() }
|
||||
override ControlFlow::Node getControlFlowNodeImpl() { result = def.getControlFlowNode() }
|
||||
|
||||
override string toString() {
|
||||
override Location getLocationImpl() { result = def.getLocation() }
|
||||
|
||||
override string toStringImpl() {
|
||||
not explicitParameterNode(this, _) and
|
||||
result = def.toString()
|
||||
}
|
||||
}
|
||||
|
||||
private module ParameterNodes {
|
||||
abstract private class ParameterNodeImpl extends ParameterNode, NodeImpl { }
|
||||
|
||||
/**
|
||||
* Holds if definition node `node` is an entry definition for parameter `p`.
|
||||
*/
|
||||
@@ -585,7 +625,7 @@ private module ParameterNodes {
|
||||
* The value of an explicit parameter at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
*/
|
||||
class ExplicitParameterNode extends ParameterNode {
|
||||
class ExplicitParameterNode extends ParameterNodeImpl {
|
||||
private DotNet::Parameter parameter;
|
||||
|
||||
ExplicitParameterNode() {
|
||||
@@ -597,17 +637,19 @@ private module ParameterNodes {
|
||||
|
||||
override predicate isParameterOf(DataFlowCallable c, int i) { c.getParameter(i) = parameter }
|
||||
|
||||
override DotNet::Callable getEnclosingCallable() { result = parameter.getCallable() }
|
||||
override DotNet::Callable getEnclosingCallableImpl() { result = parameter.getCallable() }
|
||||
|
||||
override DotNet::Type getType() { result = parameter.getType() }
|
||||
override DotNet::Type getTypeImpl() { result = parameter.getType() }
|
||||
|
||||
override Location getLocation() { result = parameter.getLocation() }
|
||||
override ControlFlow::Node getControlFlowNodeImpl() { none() }
|
||||
|
||||
override string toString() { result = parameter.toString() }
|
||||
override Location getLocationImpl() { result = parameter.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = parameter.toString() }
|
||||
}
|
||||
|
||||
/** An implicit instance (`this`) parameter. */
|
||||
class InstanceParameterNode extends ParameterNode, TInstanceParameterNode {
|
||||
class InstanceParameterNode extends ParameterNodeImpl, TInstanceParameterNode {
|
||||
private Callable callable;
|
||||
|
||||
InstanceParameterNode() { this = TInstanceParameterNode(callable) }
|
||||
@@ -617,13 +659,15 @@ private module ParameterNodes {
|
||||
|
||||
override predicate isParameterOf(DataFlowCallable c, int pos) { callable = c and pos = -1 }
|
||||
|
||||
override Callable getEnclosingCallable() { result = callable }
|
||||
override Callable getEnclosingCallableImpl() { result = callable }
|
||||
|
||||
override Type getType() { result = callable.getDeclaringType() }
|
||||
override Type getTypeImpl() { result = callable.getDeclaringType() }
|
||||
|
||||
override Location getLocation() { result = callable.getLocation() }
|
||||
override ControlFlow::Node getControlFlowNodeImpl() { none() }
|
||||
|
||||
override string toString() { result = "this" }
|
||||
override Location getLocationImpl() { result = callable.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = "this" }
|
||||
}
|
||||
|
||||
module ImplicitCapturedParameterNodeImpl {
|
||||
@@ -776,7 +820,7 @@ private module ArgumentNodes {
|
||||
* } }
|
||||
* ```
|
||||
*/
|
||||
class ImplicitCapturedArgumentNode extends ArgumentNode, TImplicitCapturedArgumentNode {
|
||||
class ImplicitCapturedArgumentNode extends ArgumentNode, NodeImpl, TImplicitCapturedArgumentNode {
|
||||
private LocalScopeVariable v;
|
||||
private ControlFlow::Nodes::ElementNode cfn;
|
||||
|
||||
@@ -814,20 +858,22 @@ private module ArgumentNodes {
|
||||
)
|
||||
}
|
||||
|
||||
override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() }
|
||||
override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() }
|
||||
|
||||
override Type getType() { result = v.getType() }
|
||||
override Type getTypeImpl() { result = v.getType() }
|
||||
|
||||
override Location getLocation() { result = cfn.getLocation() }
|
||||
override ControlFlow::Node getControlFlowNodeImpl() { none() }
|
||||
|
||||
override string toString() { result = "[implicit argument] " + v }
|
||||
override Location getLocationImpl() { result = cfn.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = "[implicit argument] " + v }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node that corresponds to the value of an object creation (`new C()`) before
|
||||
* the constructor has run.
|
||||
*/
|
||||
class MallocNode extends ArgumentNode, TMallocNode {
|
||||
class MallocNode extends ArgumentNode, NodeImpl, TMallocNode {
|
||||
private ControlFlow::Nodes::ElementNode cfn;
|
||||
|
||||
MallocNode() { this = TMallocNode(cfn) }
|
||||
@@ -837,15 +883,15 @@ private module ArgumentNodes {
|
||||
pos = -1
|
||||
}
|
||||
|
||||
override ControlFlow::Node getControlFlowNode() { result = cfn }
|
||||
override ControlFlow::Node getControlFlowNodeImpl() { result = cfn }
|
||||
|
||||
override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() }
|
||||
override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() }
|
||||
|
||||
override Type getType() { result = cfn.getElement().(Expr).getType() }
|
||||
override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() }
|
||||
|
||||
override Location getLocation() { result = cfn.getLocation() }
|
||||
override Location getLocationImpl() { result = cfn.getLocation() }
|
||||
|
||||
override string toString() { result = "malloc" }
|
||||
override string toStringImpl() { result = "malloc" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -858,7 +904,7 @@ private module ArgumentNodes {
|
||||
*
|
||||
* `x` is an implicit argument of the implicit call to `Foo`.
|
||||
*/
|
||||
class ImplicitDelegateArgumentNode extends ArgumentNode, TImplicitDelegateArgumentNode {
|
||||
class ImplicitDelegateArgumentNode extends ArgumentNode, NodeImpl, TImplicitDelegateArgumentNode {
|
||||
private ControlFlow::Node cfn;
|
||||
private int delegateIndex;
|
||||
private int parameterIndex;
|
||||
@@ -874,15 +920,17 @@ private module ArgumentNodes {
|
||||
pos = parameterIndex
|
||||
}
|
||||
|
||||
override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() }
|
||||
override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() }
|
||||
|
||||
override Type getType() {
|
||||
override Type getTypeImpl() {
|
||||
result = this.getDelegateCall().getDelegateParameterType(parameterIndex)
|
||||
}
|
||||
|
||||
override Location getLocation() { result = cfn.getLocation() }
|
||||
override ControlFlow::Node getControlFlowNodeImpl() { none() }
|
||||
|
||||
override string toString() { result = "[implicit argument " + parameterIndex + "] " + cfn }
|
||||
override Location getLocationImpl() { result = cfn.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = "[implicit argument " + parameterIndex + "] " + cfn }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -939,7 +987,7 @@ private module ReturnNodes {
|
||||
* `yield return`s as stores into collections, i.e., there is flow from `e`
|
||||
* to `yield return e [e]`.
|
||||
*/
|
||||
class YieldReturnNode extends ReturnNode, PostUpdateNode, TYieldReturnNode {
|
||||
class YieldReturnNode extends ReturnNode, NodeImpl, TYieldReturnNode {
|
||||
private ControlFlow::Nodes::ElementNode cfn;
|
||||
private YieldReturnStmt yrs;
|
||||
|
||||
@@ -949,15 +997,15 @@ private module ReturnNodes {
|
||||
|
||||
override YieldReturnKind getKind() { any() }
|
||||
|
||||
override ExprNode getPreUpdateNode() { result.getControlFlowNode() = cfn }
|
||||
override Callable getEnclosingCallableImpl() { result = yrs.getEnclosingCallable() }
|
||||
|
||||
override Callable getEnclosingCallable() { result = yrs.getEnclosingCallable() }
|
||||
override Type getTypeImpl() { result = yrs.getEnclosingCallable().getReturnType() }
|
||||
|
||||
override Type getType() { result = yrs.getEnclosingCallable().getReturnType() }
|
||||
override ControlFlow::Node getControlFlowNodeImpl() { result = cfn }
|
||||
|
||||
override Location getLocation() { result = yrs.getLocation() }
|
||||
override Location getLocationImpl() { result = yrs.getLocation() }
|
||||
|
||||
override string toString() { result = yrs.toString() }
|
||||
override string toStringImpl() { result = yrs.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1112,7 +1160,7 @@ private module OutNodes {
|
||||
* in a call to a library method. For example, the output from the implicit
|
||||
* call to `M` in `new Lazy<int>(M)`.
|
||||
*/
|
||||
class ImplicitDelegateOutNode extends OutNode, TImplicitDelegateOutNode {
|
||||
class ImplicitDelegateOutNode extends OutNode, NodeImpl, TImplicitDelegateOutNode {
|
||||
private ControlFlow::Nodes::ElementNode cfn;
|
||||
private ControlFlow::Nodes::ElementNode call;
|
||||
|
||||
@@ -1128,7 +1176,7 @@ private module OutNodes {
|
||||
call.getElement().(Call).getArgument(i) = cfn.getElement()
|
||||
}
|
||||
|
||||
override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn }
|
||||
override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() { result = cfn }
|
||||
|
||||
override ImplicitDelegateDataFlowCall getCall(ReturnKind kind) {
|
||||
result.getNode() = this and
|
||||
@@ -1141,17 +1189,17 @@ private module OutNodes {
|
||||
)
|
||||
}
|
||||
|
||||
override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() }
|
||||
override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() }
|
||||
|
||||
override Type getType() {
|
||||
override Type getTypeImpl() {
|
||||
exists(ImplicitDelegateDataFlowCall c | c.getNode() = this |
|
||||
result = c.getDelegateReturnType()
|
||||
)
|
||||
}
|
||||
|
||||
override Location getLocation() { result = cfn.getLocation() }
|
||||
override Location getLocationImpl() { result = cfn.getLocation() }
|
||||
|
||||
override string toString() { result = "[output] " + cfn }
|
||||
override string toStringImpl() { result = "[output] " + cfn }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1320,7 +1368,7 @@ module LibraryFlow {
|
||||
}
|
||||
|
||||
/** A data-flow node used to model flow through library code. */
|
||||
class LibraryCodeNode extends Node, TLibraryCodeNode {
|
||||
class LibraryCodeNode extends NodeImpl, TLibraryCodeNode {
|
||||
private ControlFlow::Node callCfn;
|
||||
private CallableFlowSource source;
|
||||
private AccessPath sourceAp;
|
||||
@@ -1413,7 +1461,7 @@ class LibraryCodeNode extends Node, TLibraryCodeNode {
|
||||
)
|
||||
}
|
||||
|
||||
override Callable getEnclosingCallable() { result = callCfn.getEnclosingCallable() }
|
||||
override Callable getEnclosingCallableImpl() { result = callCfn.getEnclosingCallable() }
|
||||
|
||||
override DataFlowType getTypeBound() {
|
||||
preservesValue = true and
|
||||
@@ -1426,9 +1474,13 @@ class LibraryCodeNode extends Node, TLibraryCodeNode {
|
||||
result = this.getSuccessor(_).getTypeBound()
|
||||
}
|
||||
|
||||
override Location getLocation() { result = callCfn.getLocation() }
|
||||
override DotNet::Type getTypeImpl() { none() }
|
||||
|
||||
override string toString() { result = "[library code] " + callCfn }
|
||||
override ControlFlow::Node getControlFlowNodeImpl() { result = callCfn }
|
||||
|
||||
override Location getLocationImpl() { result = callCfn.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = "[library code] " + callCfn }
|
||||
}
|
||||
|
||||
/** A field or a property. */
|
||||
@@ -1600,20 +1652,22 @@ private module PostUpdateNodes {
|
||||
override MallocNode getPreUpdateNode() { this = TExprNode(result.getControlFlowNode()) }
|
||||
}
|
||||
|
||||
class ExprPostUpdateNode extends PostUpdateNode, TExprPostUpdateNode {
|
||||
class ExprPostUpdateNode extends PostUpdateNode, NodeImpl, TExprPostUpdateNode {
|
||||
private ControlFlow::Nodes::ElementNode cfn;
|
||||
|
||||
ExprPostUpdateNode() { this = TExprPostUpdateNode(cfn) }
|
||||
|
||||
override ExprNode getPreUpdateNode() { cfn = result.getControlFlowNode() }
|
||||
|
||||
override Callable getEnclosingCallable() { result = cfn.getEnclosingCallable() }
|
||||
override Callable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() }
|
||||
|
||||
override Type getType() { result = cfn.getElement().(Expr).getType() }
|
||||
override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() }
|
||||
|
||||
override Location getLocation() { result = cfn.getLocation() }
|
||||
override ControlFlow::Node getControlFlowNodeImpl() { none() }
|
||||
|
||||
override string toString() { result = "[post] " + cfn.toString() }
|
||||
override Location getLocationImpl() { result = cfn.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = "[post] " + cfn.toString() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,9 @@ class Node extends TNode {
|
||||
|
||||
/** Gets the type of this node. */
|
||||
cached
|
||||
DotNet::Type getType() { none() }
|
||||
final DotNet::Type getType() {
|
||||
Stages::DataFlowStage::forceCachingInSameStage() and result = this.(NodeImpl).getTypeImpl()
|
||||
}
|
||||
|
||||
/** INTERNAL: Do not use. Gets an upper bound on the type of this node. */
|
||||
cached
|
||||
@@ -55,19 +57,31 @@ class Node extends TNode {
|
||||
|
||||
/** Gets the enclosing callable of this node. */
|
||||
cached
|
||||
DataFlowCallable getEnclosingCallable() { none() }
|
||||
final DataFlowCallable getEnclosingCallable() {
|
||||
Stages::DataFlowStage::forceCachingInSameStage() and
|
||||
result = unique(DataFlowCallable c | c = this.(NodeImpl).getEnclosingCallableImpl() | c)
|
||||
}
|
||||
|
||||
/** Gets the control flow node corresponding to this node, if any. */
|
||||
cached
|
||||
ControlFlow::Node getControlFlowNode() { none() }
|
||||
final ControlFlow::Node getControlFlowNode() {
|
||||
Stages::DataFlowStage::forceCachingInSameStage() and
|
||||
result = unique(ControlFlow::Node n | n = this.(NodeImpl).getControlFlowNodeImpl() | n)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this node. */
|
||||
cached
|
||||
string toString() { none() }
|
||||
final string toString() {
|
||||
Stages::DataFlowStage::forceCachingInSameStage() and
|
||||
result = this.(NodeImpl).toStringImpl()
|
||||
}
|
||||
|
||||
/** Gets the location of this node. */
|
||||
cached
|
||||
Location getLocation() { none() }
|
||||
final Location getLocation() {
|
||||
Stages::DataFlowStage::forceCachingInSameStage() and
|
||||
result = this.(NodeImpl).getLocationImpl()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
@@ -108,31 +122,6 @@ class ExprNode extends Node {
|
||||
this = TExprNode(cfn) and
|
||||
result = cfn.getElement()
|
||||
}
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
Stages::DataFlowStage::forceCachingInSameStage() and
|
||||
result = this.getExpr().getEnclosingCallable()
|
||||
}
|
||||
|
||||
override ControlFlow::Nodes::ElementNode getControlFlowNode() {
|
||||
Stages::DataFlowStage::forceCachingInSameStage() and this = TExprNode(result)
|
||||
}
|
||||
|
||||
override DotNet::Type getType() {
|
||||
Stages::DataFlowStage::forceCachingInSameStage() and result = this.getExpr().getType()
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
Stages::DataFlowStage::forceCachingInSameStage() and result = this.getExpr().getLocation()
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
Stages::DataFlowStage::forceCachingInSameStage() and
|
||||
result = this.getControlFlowNode().toString()
|
||||
or
|
||||
this = TCilExprNode(_) and
|
||||
result = "CIL expression"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -159,7 +159,8 @@ module Cached {
|
||||
Stages::DataFlowStage::forceCachingInSameStage() and
|
||||
any(LocalTaintExprStepConfiguration x).hasNodePath(nodeFrom, nodeTo)
|
||||
or
|
||||
nodeFrom = nodeTo.(YieldReturnNode).getPreUpdateNode()
|
||||
nodeFrom.(DataFlow::ExprNode).getControlFlowNode() =
|
||||
nodeTo.(YieldReturnNode).getControlFlowNode()
|
||||
or
|
||||
localTaintStepCil(nodeFrom, nodeTo)
|
||||
or
|
||||
|
||||
Reference in New Issue
Block a user