Skip to content

Commit bab5e7e

Browse files
committed
Data flow: Move C# lambda flow logic into shared library
1 parent 0eb2c06 commit bab5e7e

File tree

9 files changed

+458
-128
lines changed

9 files changed

+458
-128
lines changed

csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,43 @@ private newtype TCallContext =
1515
TArgFunctionPointerCallContext(FunctionPointerCall fptrc, int i) { exists(fptrc.getArgument(i)) }
1616

1717
/**
18+
* DEPRECATED.
19+
*
1820
* A call context.
1921
*
2022
* A call context records the origin of data flow into callables.
2123
*/
22-
class CallContext extends TCallContext {
24+
deprecated class CallContext extends TCallContext {
2325
/** Gets a textual representation of this call context. */
2426
string toString() { none() }
2527

2628
/** Gets the location of this call context, if any. */
2729
Location getLocation() { none() }
2830
}
2931

30-
/** An empty call context. */
31-
class EmptyCallContext extends CallContext, TEmptyCallContext {
32+
/** DEPRECATED. An empty call context. */
33+
deprecated class EmptyCallContext extends CallContext, TEmptyCallContext {
3234
override string toString() { result = "<empty>" }
3335

3436
override EmptyLocation getLocation() { any() }
3537
}
3638

3739
/**
40+
* DEPRECATED.
41+
*
3842
* An argument call context, that is a call argument through which data flows
3943
* into a callable.
4044
*/
41-
abstract class ArgumentCallContext extends CallContext {
45+
deprecated abstract class ArgumentCallContext extends CallContext {
4246
/**
4347
* Holds if this call context represents the argument at position `i` of the
4448
* call expression `call`.
4549
*/
4650
abstract predicate isArgument(Expr call, int i);
4751
}
4852

49-
/** An argument of a non-delegate call. */
50-
class NonDelegateCallArgumentCallContext extends ArgumentCallContext, TArgNonDelegateCallContext {
53+
/** DEPRECATED. An argument of a non-delegate call. */
54+
deprecated class NonDelegateCallArgumentCallContext extends ArgumentCallContext, TArgNonDelegateCallContext {
5155
Expr arg;
5256

5357
NonDelegateCallArgumentCallContext() { this = TArgNonDelegateCallContext(arg) }
@@ -61,8 +65,8 @@ class NonDelegateCallArgumentCallContext extends ArgumentCallContext, TArgNonDel
6165
override Location getLocation() { result = arg.getLocation() }
6266
}
6367

64-
/** An argument of a delegate or function pointer call. */
65-
class DelegateLikeCallArgumentCallContext extends ArgumentCallContext {
68+
/** DEPRECATED. An argument of a delegate or function pointer call. */
69+
deprecated class DelegateLikeCallArgumentCallContext extends ArgumentCallContext {
6670
DelegateLikeCall dc;
6771
int arg;
6872

@@ -80,10 +84,10 @@ class DelegateLikeCallArgumentCallContext extends ArgumentCallContext {
8084
override Location getLocation() { result = dc.getArgument(arg).getLocation() }
8185
}
8286

83-
/** An argument of a delegate call. */
84-
class DelegateCallArgumentCallContext extends DelegateLikeCallArgumentCallContext,
87+
/** DEPRECATED. An argument of a delegate call. */
88+
deprecated class DelegateCallArgumentCallContext extends DelegateLikeCallArgumentCallContext,
8589
TArgDelegateCallContext { }
8690

87-
/** An argument of a function pointer call. */
88-
class FunctionPointerCallArgumentCallContext extends DelegateLikeCallArgumentCallContext,
91+
/** DEPRECATED. An argument of a function pointer call. */
92+
deprecated class FunctionPointerCallArgumentCallContext extends DelegateLikeCallArgumentCallContext,
8993
TArgFunctionPointerCallContext { }

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

Lines changed: 12 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
private import csharp
22
private import cil
33
private import dotnet
4+
private import DataFlowPublic
45
private import DataFlowPrivate
5-
private import DelegateDataFlow
66
private import FlowSummaryImpl as FlowSummaryImpl
77
private import semmle.code.csharp.dataflow.FlowSummary
88
private import semmle.code.csharp.dispatch.Dispatch
@@ -131,45 +131,24 @@ private module Cached {
131131
import Cached
132132

133133
private module DispatchImpl {
134-
private import CallContext
135-
136-
/**
137-
* Gets a viable run-time target for the delegate call `call`, requiring
138-
* call context `cc`.
139-
*/
140-
private DataFlowCallable viableDelegateCallable(DataFlowCall call, CallContext cc) {
141-
result = call.(DelegateDataFlowCall).getARuntimeTarget(cc)
142-
}
143-
144134
/**
145135
* Holds if the set of viable implementations that can be called by `call`
146136
* might be improved by knowing the call context. This is the case if the
147137
* call is a delegate call, or if the qualifier accesses a parameter of
148138
* the enclosing callable `c` (including the implicit `this` parameter).
149139
*/
150-
predicate mayBenefitFromCallContext(DataFlowCall call, Callable c) {
140+
predicate mayBenefitFromCallContext(NonDelegateDataFlowCall call, Callable c) {
151141
c = call.getEnclosingCallable() and
152-
(
153-
exists(CallContext cc | exists(viableDelegateCallable(call, cc)) |
154-
not cc instanceof EmptyCallContext
155-
)
156-
or
157-
call.(NonDelegateDataFlowCall).getDispatchCall().mayBenefitFromCallContext()
158-
)
142+
call.getDispatchCall().mayBenefitFromCallContext()
159143
}
160144

161145
/**
162146
* Gets a viable dispatch target of `call` in the context `ctx`. This is
163147
* restricted to those `call`s for which a context might make a difference.
164148
*/
165-
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
166-
exists(ArgumentCallContext cc | result = viableDelegateCallable(call, cc) |
167-
cc.isArgument(ctx.getExpr(), _)
168-
)
169-
or
149+
DataFlowCallable viableImplInCallContext(NonDelegateDataFlowCall call, DataFlowCall ctx) {
170150
result =
171-
call.(NonDelegateDataFlowCall)
172-
.getDispatchCall()
151+
call.getDispatchCall()
173152
.getADynamicTargetInCallContext(ctx.(NonDelegateDataFlowCall).getDispatchCall())
174153
.getUnboundDeclaration()
175154
}
@@ -302,10 +281,9 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
302281

303282
/** A delegate call relevant for data flow. */
304283
abstract class DelegateDataFlowCall extends DataFlowCall {
305-
/** Gets a viable run-time target of this call requiring call context `cc`. */
306-
abstract DataFlowCallable getARuntimeTarget(CallContext::CallContext cc);
307-
308-
override DataFlowCallable getARuntimeTarget() { result = this.getARuntimeTarget(_) }
284+
override DataFlowCallable getARuntimeTarget() {
285+
none() // handled by the shared library
286+
}
309287
}
310288

311289
/** An explicit delegate or function pointer call relevant for data flow. */
@@ -315,9 +293,8 @@ class ExplicitDelegateLikeDataFlowCall extends DelegateDataFlowCall, TExplicitDe
315293

316294
ExplicitDelegateLikeDataFlowCall() { this = TExplicitDelegateLikeCall(cfn, dc) }
317295

318-
override DataFlowCallable getARuntimeTarget(CallContext::CallContext cc) {
319-
result = getCallableForDataFlow(dc.getARuntimeTarget(cc))
320-
}
296+
/** Gets the underlying call. */
297+
DelegateLikeCall getCall() { result = dc }
321298

322299
override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn }
323300

@@ -389,12 +366,8 @@ class SummaryDelegateCall extends DelegateDataFlowCall, TSummaryDelegateCall {
389366

390367
SummaryDelegateCall() { this = TSummaryDelegateCall(c, pos) }
391368

392-
override DataFlowCallable getARuntimeTarget(CallContext::CallContext cc) {
393-
exists(SummaryDelegateParameterSink p |
394-
p.isParameterOf(c, pos) and
395-
result = p.getARuntimeTarget(cc)
396-
)
397-
}
369+
/** Gets the parameter node that this delegate call targets. */
370+
ParameterNode getParameterNode() { result.isParameterOf(c, pos) }
398371

399372
override ControlFlow::Nodes::ElementNode getControlFlowNode() { none() }
400373

0 commit comments

Comments
 (0)