Merge pull request #3652 from hvitved/csharp/dataflow/impl-layer

C#: Refactor data-flow predicates defined by dispatch
This commit is contained in:
Calum Grant
2020-06-11 10:01:50 +01:00
committed by GitHub
3 changed files with 127 additions and 83 deletions

View File

@@ -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() }
}
}

View File

@@ -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"
}
}
/**

View File

@@ -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