Merge pull request #5725 from hvitved/csharp/dataflow/performance

C#: Various data-flow performance tweaks
This commit is contained in:
Tom Hvitved
2021-04-21 09:46:15 +02:00
committed by GitHub
4 changed files with 69 additions and 61 deletions

View File

@@ -49,6 +49,7 @@ module Stages {
cached
module DataFlowStage {
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate
@@ -78,6 +79,8 @@ module Stages {
or
exists(CallContext cc)
or
exists(any(DataFlowCall c).getEnclosingCallable())
or
forceCachingInSameStageRev()
}
}

View File

@@ -4,6 +4,7 @@ private import dotnet
private import DataFlowPublic
private import DataFlowPrivate
private import FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.csharp.Caching
private import semmle.code.csharp.dataflow.FlowSummary
private import semmle.code.csharp.dispatch.Dispatch
private import semmle.code.csharp.frameworks.system.Collections
@@ -69,8 +70,6 @@ private predicate transitiveCapturedCallTarget(ControlFlow::Nodes::ElementNode c
cached
private module Cached {
private import semmle.code.csharp.Caching
cached
newtype TReturnKind =
TNormalReturnKind() { Stages::DataFlowStage::forceCachingInSameStage() } or
@@ -247,6 +246,7 @@ abstract class DataFlowCall extends TDataFlowCall {
abstract DataFlow::Node getNode();
/** Gets the enclosing callable of this call. */
cached
abstract DataFlowCallable getEnclosingCallable();
/** Gets the underlying expression, if any. */
@@ -280,7 +280,10 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn }
override DataFlowCallable getEnclosingCallable() { result = cfn.getEnclosingCallable() }
override DataFlowCallable getEnclosingCallable() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = cfn.getEnclosingCallable()
}
override string toString() { result = cfn.toString() }

View File

@@ -21,9 +21,11 @@ private import semmle.code.csharp.frameworks.system.threading.Tasks
abstract class NodeImpl extends Node {
/** Do not call: use `getEnclosingCallable()` instead. */
cached
abstract DataFlowCallable getEnclosingCallableImpl();
/** Do not call: use `getType()` instead. */
cached
abstract DotNet::Type getTypeImpl();
/** Gets the type of this node used for type pruning. */
@@ -39,27 +41,39 @@ abstract class NodeImpl extends Node {
}
/** Do not call: use `getControlFlowNode()` instead. */
cached
abstract ControlFlow::Node getControlFlowNodeImpl();
/** Do not call: use `getLocation()` instead. */
cached
abstract Location getLocationImpl();
/** Do not call: use `toString()` instead. */
cached
abstract string toStringImpl();
}
private class ExprNodeImpl extends ExprNode, NodeImpl {
override DataFlowCallable getEnclosingCallableImpl() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = this.getExpr().getEnclosingCallable()
}
override DotNet::Type getTypeImpl() { result = this.getExpr().getType() }
override DotNet::Type getTypeImpl() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = this.getExpr().getType()
}
override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() { this = TExprNode(result) }
override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() {
Stages::DataFlowStage::forceCachingInSameStage() and this = TExprNode(result)
}
override Location getLocationImpl() { result = this.getExpr().getLocation() }
override Location getLocationImpl() {
Stages::DataFlowStage::forceCachingInSameStage() and result = this.getExpr().getLocation()
}
override string toStringImpl() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = this.getControlFlowNode().toString()
or
exists(CIL::Expr e |
@@ -967,6 +981,16 @@ private module Cached {
or
n.asExpr() = any(WithExpr we).getInitializer()
}
cached
predicate parameterNode(Node n, DataFlowCallable c, int i) {
n.(ParameterNodeImpl).isParameterOf(c, i)
}
cached
predicate argumentNode(Node n, DataFlowCall call, int pos) {
n.(ArgumentNodeImpl).argumentOf(call, pos)
}
}
import Cached
@@ -992,8 +1016,6 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
}
abstract class ParameterNodeImpl extends NodeImpl {
abstract DotNet::Parameter getParameter();
abstract predicate isParameterOf(DataFlowCallable c, int i);
}
@@ -1010,11 +1032,9 @@ private module ParameterNodes {
/** Gets the SSA definition corresponding to this parameter, if any. */
Ssa::ExplicitDefinition getSsaDefinition() {
result.getADefinition().(AssignableDefinitions::ImplicitParameterDefinition).getParameter() =
this.getParameter()
parameter
}
override DotNet::Parameter getParameter() { result = parameter }
override predicate isParameterOf(DataFlowCallable c, int i) { c.getParameter(i) = parameter }
override DataFlowCallable getEnclosingCallableImpl() { result = parameter.getCallable() }
@@ -1037,8 +1057,6 @@ private module ParameterNodes {
/** Gets the callable containing this implicit instance parameter. */
Callable getCallable() { result = callable }
override DotNet::Parameter getParameter() { none() }
override predicate isParameterOf(DataFlowCallable c, int pos) { callable = c and pos = -1 }
override DataFlowCallable getEnclosingCallableImpl() { result = callable }
@@ -1113,8 +1131,6 @@ private module ParameterNodes {
/** Gets the captured variable that this implicit parameter models. */
LocalScopeVariable getVariable() { result = def.getVariable() }
override DotNet::Parameter getParameter() { none() }
override predicate isParameterOf(DataFlowCallable c, int i) {
i = getParameterPosition(def) and
c = this.getEnclosingCallable()
@@ -1125,13 +1141,15 @@ private module ParameterNodes {
import ParameterNodes
/** A data-flow node that represents a call argument. */
abstract class ArgumentNode extends Node {
/** Holds if this argument occurs at the given position in the given call. */
cached
abstract predicate argumentOf(DataFlowCall call, int pos);
class ArgumentNode extends Node {
ArgumentNode() { argumentNode(this, _, _) }
/** Gets the call in which this node is an argument. */
final DataFlowCall getCall() { this.argumentOf(result, _) }
/** Holds if this argument occurs at the given position in the given call. */
final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
}
abstract private class ArgumentNodeImpl extends Node {
abstract predicate argumentOf(DataFlowCall call, int pos);
}
private module ArgumentNodes {
@@ -1149,7 +1167,7 @@ private module ArgumentNodes {
}
/** A data-flow node that represents an explicit call argument. */
class ExplicitArgumentNode extends ArgumentNode {
class ExplicitArgumentNode extends ArgumentNodeImpl {
ExplicitArgumentNode() {
this.asExpr() instanceof Argument
or
@@ -1157,7 +1175,6 @@ private module ArgumentNodes {
}
override predicate argumentOf(DataFlowCall call, int pos) {
Stages::DataFlowStage::forceCachingInSameStage() and
exists(ArgumentConfiguration x, Expr c, Argument arg |
arg = this.asExpr() and
c = call.getExpr() and
@@ -1189,7 +1206,8 @@ private module ArgumentNodes {
* } }
* ```
*/
class ImplicitCapturedArgumentNode extends ArgumentNode, NodeImpl, TImplicitCapturedArgumentNode {
class ImplicitCapturedArgumentNode extends ArgumentNodeImpl, NodeImpl,
TImplicitCapturedArgumentNode {
private LocalScopeVariable v;
private ControlFlow::Nodes::ElementNode cfn;
@@ -1231,7 +1249,7 @@ private module ArgumentNodes {
* A node that corresponds to the value of an object creation (`new C()`) before
* the constructor has run.
*/
class MallocNode extends ArgumentNode, NodeImpl, TMallocNode {
class MallocNode extends ArgumentNodeImpl, NodeImpl, TMallocNode {
private ControlFlow::Nodes::ElementNode cfn;
MallocNode() { this = TMallocNode(cfn) }
@@ -1266,7 +1284,7 @@ private module ArgumentNodes {
* and that argument is itself a compatible array, for example
* `Foo(new[] { "a", "b", "c" })`.
*/
class ParamsArgumentNode extends ArgumentNode, NodeImpl, TParamsArgumentNode {
class ParamsArgumentNode extends ArgumentNodeImpl, NodeImpl, TParamsArgumentNode {
private ControlFlow::Node callCfn;
ParamsArgumentNode() { this = TParamsArgumentNode(callCfn) }
@@ -1291,7 +1309,7 @@ private module ArgumentNodes {
override string toStringImpl() { result = "[implicit array creation] " + callCfn }
}
private class SummaryArgumentNode extends SummaryNode, ArgumentNode {
private class SummaryArgumentNode extends SummaryNode, ArgumentNodeImpl {
private DataFlowCall c;
private int i;
@@ -1324,10 +1342,7 @@ private module ReturnNodes {
)
}
override NormalReturnKind getKind() {
any(DotNet::Callable c).canReturn(this.getExpr()) and
exists(result)
}
override NormalReturnKind getKind() { exists(result) }
}
/**
@@ -1744,7 +1759,10 @@ class DataFlowType extends Gvn::GvnType {
}
/** Gets the type of `n` used for type pruning. */
DataFlowType getNodeType(NodeImpl n) { result = n.getDataFlowType() }
pragma[inline]
Gvn::GvnType getNodeType(NodeImpl n) {
pragma[only_bind_into](result) = pragma[only_bind_out](n).getDataFlowType()
}
/** Gets a string representation of a `DataFlowType`. */
string ppReprType(DataFlowType t) { result = t.toString() }
@@ -1819,7 +1837,8 @@ private module PostUpdateNodes {
* Such a node acts as both a post-update node for the `MallocNode`, as well as
* a pre-update node for the `ObjectCreationNode`.
*/
class ObjectInitializerNode extends PostUpdateNode, NodeImpl, ArgumentNode, TObjectInitializerNode {
class ObjectInitializerNode extends PostUpdateNode, NodeImpl, ArgumentNodeImpl,
TObjectInitializerNode {
private ObjectCreation oc;
private ControlFlow::Nodes::ElementNode cfn;

View File

@@ -3,7 +3,6 @@ private import cil
private import dotnet
private import DataFlowDispatch
private import DataFlowPrivate
private import semmle.code.csharp.Caching
private import semmle.code.csharp.controlflow.Guards
private import semmle.code.csharp.Unification
@@ -38,38 +37,21 @@ class Node extends TNode {
}
/** Gets the type of this node. */
cached
final DotNet::Type getType() {
Stages::DataFlowStage::forceCachingInSameStage() and result = this.(NodeImpl).getTypeImpl()
}
final DotNet::Type getType() { result = this.(NodeImpl).getTypeImpl() }
/** Gets the enclosing callable of this node. */
cached
final DataFlowCallable getEnclosingCallable() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = this.(NodeImpl).getEnclosingCallableImpl()
}
/** Gets the control flow node corresponding to this node, if any. */
cached
final ControlFlow::Node getControlFlowNode() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = this.(NodeImpl).getControlFlowNodeImpl()
}
final ControlFlow::Node getControlFlowNode() { result = this.(NodeImpl).getControlFlowNodeImpl() }
/** Gets a textual representation of this node. */
cached
final string toString() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = this.(NodeImpl).toStringImpl()
}
final string toString() { result = this.(NodeImpl).toStringImpl() }
/** Gets the location of this node. */
cached
final Location getLocation() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = this.(NodeImpl).getLocationImpl()
}
final Location getLocation() { result = this.(NodeImpl).getLocationImpl() }
/**
* Holds if this element is at the specified location.
@@ -81,7 +63,7 @@ class Node extends TNode {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
@@ -117,18 +99,18 @@ class ExprNode extends Node {
* flow graph.
*/
class ParameterNode extends Node {
private ParameterNodeImpl p;
ParameterNode() { this = p }
ParameterNode() { parameterNode(this, _, _) }
/** Gets the parameter corresponding to this node, if any. */
DotNet::Parameter getParameter() { result = p.getParameter() }
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) { p.isParameterOf(c, i) }
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
}
/** A definition, viewed as a node in a data flow graph. */
@@ -166,6 +148,7 @@ 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) }
/**