Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2a2e07d

Browse files
committed
C#: Avoid recomputation in last data flow stage
Avoid recomputing the `ControlFlowReachabilityConfiguration` predicates, as well as `DispatchCall::getStaticTarget()`.
1 parent d175550 commit 2a2e07d

2 files changed

Lines changed: 50 additions & 48 deletions

File tree

csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll

Lines changed: 47 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,16 @@ private module ParameterNodes {
608608
}
609609
import ParameterNodes
610610

611+
/** A data flow node that represents a call argument. */
612+
abstract class ArgumentNode extends Node {
613+
/** Holds if this argument occurs at the given position in the given call. */
614+
cached
615+
abstract predicate argumentOf(DataFlowCall call, int pos);
616+
617+
/** Gets the call in which this node is an argument. */
618+
final DataFlowCall getCall() { this.argumentOf(result, _) }
619+
}
620+
611621
private module ArgumentNodes {
612622
class DelegateArgumentConfiguration extends ControlFlowReachabilityConfiguration {
613623
DelegateArgumentConfiguration() { this = "DelegateArgumentConfiguration" }
@@ -625,9 +635,9 @@ private module ArgumentNodes {
625635
}
626636

627637
/**
628-
* Holds if `arg` is an argument of the call `call`, which resolves to a
629-
* library callable that is known to forward `arg` into the `i`th parameter
630-
* of a supplied delegate `delegate`.
638+
* Holds if `arg` is an argument of a call, which resolves to a library callable
639+
* that is known to forward `arg` into the `i`th parameter of a supplied
640+
* delegate `delegate`.
631641
*
632642
* For example, in
633643
*
@@ -638,9 +648,9 @@ private module ArgumentNodes {
638648
* `arg = x`, `i = 0`, `call = x.Select(Foo)`, and `delegate = Foo`.
639649
*/
640650
private predicate flowIntoCallableLibraryCall(
641-
DataFlowCall call, Node arg, ImplicitDelegateDataFlowCall delegate, int i
651+
ExplicitArgumentNode arg, ImplicitDelegateDataFlowCall delegate, int i
642652
) {
643-
exists(int j, boolean preservesValue |
653+
exists(DataFlowCall call, int j, boolean preservesValue |
644654
preservesValue = true and i = j
645655
or
646656
preservesValue = false and i = j + delegate.getNumberOfDelegateParameters()
@@ -678,43 +688,34 @@ private module ArgumentNodes {
678688
}
679689
}
680690

681-
/** A data flow node that represents a call argument. */
682-
abstract class ArgumentNode extends Node {
683-
/** Holds if this argument occurs at the given position in the given call. */
684-
cached
685-
abstract predicate argumentOf(DataFlowCall call, int pos);
686-
687-
/** Gets the call in which this node is an argument. */
688-
final DataFlowCall getCall() { this.argumentOf(result, _) }
689-
}
690-
691691
/** A data flow node that represents an explicit call argument. */
692692
private class ExplicitArgumentNode extends ArgumentNode {
693-
private DataFlowCall c;
694-
695-
private int i;
696-
697693
ExplicitArgumentNode() {
698-
exists(ArgumentConfiguration x, Expr call, Argument arg |
699-
arg = this.asExpr() and
700-
call = c.getExpr() and
701-
arg.isArgumentOf(call, i) and
702-
x.hasExprPath(_, this.getControlFlowNode(), _, c.getControlFlowNode())
703-
)
694+
this.asExpr() instanceof Argument
704695
or
705-
exists(CIL::Call call, CIL::Expr arg |
706-
arg = this.asExpr() and
707-
call = c.getExpr() and
708-
arg = call.getArgument(i)
709-
)
696+
this.asExpr() = any(CIL::Call call).getAnArgument()
697+
or
698+
libraryFlowDelegateCallIn(_, _, this.asExpr(), _, _, _)
710699
or
711-
flowIntoCallableLibraryCall(_, this, c, i)
700+
this.(ImplicitDelegateOutNode).isArgumentOf(_, _)
712701
}
713702

714703
override predicate argumentOf(DataFlowCall call, int pos) {
715704
Stages::DataFlowStage::forceCachingInSameStage() and
716-
call = c and
717-
pos = i
705+
exists(ArgumentConfiguration x, Expr c, Argument arg |
706+
arg = this.asExpr() and
707+
c = call.getExpr() and
708+
arg.isArgumentOf(c, pos) and
709+
x.hasExprPath(_, this.getControlFlowNode(), _, call.getControlFlowNode())
710+
)
711+
or
712+
exists(CIL::Call c, CIL::Expr arg |
713+
arg = this.asExpr() and
714+
c = call.getExpr() and
715+
arg = c.getArgument(pos)
716+
)
717+
or
718+
flowIntoCallableLibraryCall(this, call, pos)
718719
}
719720
}
720721

@@ -849,13 +850,13 @@ private module ArgumentNodes {
849850
}
850851
import ArgumentNodes
851852

852-
private module ReturnNodes {
853-
/** A data flow node that represents a value returned by a callable. */
854-
abstract class ReturnNode extends Node {
855-
/** Gets the kind of this return node. */
856-
abstract ReturnKind getKind();
857-
}
853+
/** A data flow node that represents a value returned by a callable. */
854+
abstract class ReturnNode extends Node {
855+
/** Gets the kind of this return node. */
856+
abstract ReturnKind getKind();
857+
}
858858

859+
private module ReturnNodes {
859860
/**
860861
* A data flow node that represents an expression returned by a callable,
861862
* either using a (`yield`) `return` statement or an expression body (`=>`).
@@ -962,14 +963,14 @@ private module ReturnNodes {
962963
}
963964
import ReturnNodes
964965

965-
private module OutNodes {
966-
/** A data flow node that represents the output of a call. */
967-
abstract class OutNode extends Node {
968-
/** Gets the underlying call. */
969-
cached
970-
abstract DataFlowCall getCall();
971-
}
966+
/** A data flow node that represents the output of a call. */
967+
abstract class OutNode extends Node {
968+
/** Gets the underlying call. */
969+
cached
970+
abstract DataFlowCall getCall();
971+
}
972972

973+
private module OutNodes {
973974
private DataFlowCall csharpCall(Expr e, ControlFlow::Node cfn) {
974975
e = any(DispatchCall dc | result = TNonDelegateCall(cfn, dc)).getCall() or
975976
result = TExplicitDelegateCall(cfn, e)

csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,16 @@ private module Internal {
8383
cached
8484
Expr getQualifier(DispatchCall dc) { result = dc.(DispatchCallImpl).getQualifier() }
8585

86+
cached
87+
Callable getAStaticTarget(DispatchCall dc) { result = dc.(DispatchCallImpl).getAStaticTarget() }
88+
8689
cached
8790
RuntimeCallable getADynamicTarget(DispatchCall dc) {
8891
result = dc.(DispatchCallImpl).getADynamicTarget()
8992
}
9093
}
9194
import Cached
9295

93-
Callable getAStaticTarget(DispatchCall dc) { result = dc.(DispatchCallImpl).getAStaticTarget() }
94-
9596
/**
9697
* Holds if `mc` is a reflection call to a method named `name`, where
9798
* `object` is the object on which to invoke the method (`null` if a

0 commit comments

Comments
 (0)