Skip to content

Commit 7d62e33

Browse files
committed
C#: Rework function pointer/delegate call DF
1 parent 91152d3 commit 7d62e33

File tree

14 files changed

+133
-275
lines changed

14 files changed

+133
-275
lines changed

csharp/ql/src/Dead Code/DeadStoreOfLocal.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ predicate mayEscape(LocalVariable v) {
6363
exists(Callable c, Expr e, Expr succ | c = getACapturingCallableAncestor(v) |
6464
e = getADelegateExpr(c) and
6565
DataFlow::localExprFlow(e, succ) and
66-
not succ = any(DelegateCall dc).getDelegateExpr() and
66+
not succ = any(DelegateCall dc).getExpr() and
6767
not succ = any(Cast cast).getExpr() and
6868
not succ = any(Call call | nonEscapingCall(call)).getAnArgument() and
6969
not succ = any(AssignableDefinition ad | ad.getTarget() instanceof LocalVariable).getSource()

csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,7 @@ private class TranslatedDelegateInvokeCall extends TranslatedCompilerGeneratedCa
9797
)
9898
}
9999

100-
override TranslatedExprBase getQualifier() {
101-
result = getTranslatedExpr(generatedBy.getDelegateExpr())
102-
}
100+
override TranslatedExprBase getQualifier() { result = getTranslatedExpr(generatedBy.getExpr()) }
103101

104102
override Instruction getQualifierResult() { result = getQualifier().getResult() }
105103

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

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ cached
1111
private newtype TCallContext =
1212
TEmptyCallContext() or
1313
TArgNonDelegateCallContext(Expr arg) { exists(DispatchCall dc | arg = dc.getArgument(_)) } or
14-
TArgDelegateCallContext(DelegateCall dc, int i) { exists(dc.getArgument(i)) }
14+
TArgDelegateCallContext(DelegateCall dc, int i) { exists(dc.getArgument(i)) } or
15+
TArgFunctionPointerCallContext(FunctionPointerCall fptrc, int i) { exists(fptrc.getArgument(i)) }
1516

1617
/**
1718
* A call context.
@@ -60,12 +61,14 @@ class NonDelegateCallArgumentCallContext extends ArgumentCallContext, TArgNonDel
6061
override Location getLocation() { result = arg.getLocation() }
6162
}
6263

63-
/** An argument of a delegate call. */
64-
class DelegateCallArgumentCallContext extends ArgumentCallContext, TArgDelegateCallContext {
65-
DelegateCall dc;
64+
/** An argument of a delegate or function pointer call. */
65+
class DelegateLikeCallArgumentCallContext extends ArgumentCallContext {
66+
DelegateLikeCall dc;
6667
int arg;
6768

68-
DelegateCallArgumentCallContext() { this = TArgDelegateCallContext(dc, arg) }
69+
DelegateLikeCallArgumentCallContext() {
70+
this = TArgDelegateCallContext(dc, arg) or this = TArgFunctionPointerCallContext(dc, arg)
71+
}
6972

7073
override predicate isArgument(Expr call, int i) {
7174
call = dc and
@@ -76,3 +79,15 @@ class DelegateCallArgumentCallContext extends ArgumentCallContext, TArgDelegateC
7679

7780
override Location getLocation() { result = dc.getArgument(arg).getLocation() }
7881
}
82+
83+
/** An argument of a delegate call. */
84+
class DelegateCallArgumentCallContext extends DelegateLikeCallArgumentCallContext,
85+
TArgDelegateCallContext {
86+
DelegateCallArgumentCallContext() { this = TArgDelegateCallContext(dc, arg) }
87+
}
88+
89+
/** An argument of a function pointer call. */
90+
class FunctionPointerCallArgumentCallContext extends DelegateLikeCallArgumentCallContext,
91+
TArgFunctionPointerCallContext {
92+
FunctionPointerCallArgumentCallContext() { this = TArgFunctionPointerCallContext(dc, arg) }
93+
}

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

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,14 @@ private import semmle.code.csharp.dataflow.FlowSummary
1414
private import semmle.code.csharp.dispatch.Dispatch
1515
private import semmle.code.csharp.frameworks.system.linq.Expressions
1616

17+
/** A source of flow for a delegate or function pointer expression. */
18+
private class DelegateLikeFlowSource extends DataFlow::ExprNode {
19+
/** Gets the callable that is referenced in this delegate or function pointer flow source. */
20+
Callable getCallable() { none() }
21+
}
22+
1723
/** A source of flow for a delegate expression. */
18-
private class DelegateFlowSource extends DataFlow::ExprNode {
24+
private class DelegateFlowSource extends DelegateLikeFlowSource {
1925
Callable c;
2026

2127
DelegateFlowSource() {
@@ -27,11 +33,26 @@ private class DelegateFlowSource extends DataFlow::ExprNode {
2733
}
2834

2935
/** Gets the callable that is referenced in this delegate flow source. */
30-
Callable getCallable() { result = c }
36+
override Callable getCallable() { result = c }
37+
}
38+
39+
/** A source of flow for a function pointer expression. */
40+
private class FunctionPointerFlowSource extends DelegateLikeFlowSource {
41+
Callable c;
42+
43+
FunctionPointerFlowSource() {
44+
this.getExpr() =
45+
any(Expr e |
46+
c = e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration()
47+
)
48+
}
49+
50+
/** Gets the callable that is referenced in this function pointer flow source. */
51+
override Callable getCallable() { result = c }
3152
}
3253

33-
/** A sink of flow for a delegate expression. */
34-
abstract private class DelegateFlowSink extends DataFlow::Node {
54+
/** A sink of flow for a delegate or function pointer expression. */
55+
abstract private class DelegateLikeFlowSink extends DataFlow::Node {
3556
/**
3657
* Gets an actual run-time target of this delegate call in the given call
3758
* context, if any. The call context records the *last* call required to
@@ -85,33 +106,49 @@ abstract private class DelegateFlowSink extends DataFlow::Node {
85106
*/
86107
cached
87108
Callable getARuntimeTarget(CallContext context) {
88-
exists(DelegateFlowSource dfs |
109+
exists(DelegateLikeFlowSource dfs |
89110
flowsFrom(this, dfs, _, context) and
90111
result = dfs.getCallable()
91112
)
92113
}
93114
}
94115

116+
/** A delegate or function pointer call expression. */
117+
class DelegateLikeCallExpr extends DelegateLikeFlowSink, DataFlow::ExprNode {
118+
/** Gets the delegate or function pointer call that this expression belongs to. */
119+
DelegateLikeCall getCall() { none() }
120+
}
121+
95122
/** A delegate call expression. */
96-
class DelegateCallExpr extends DelegateFlowSink, DataFlow::ExprNode {
123+
class DelegateCallExpr extends DelegateLikeCallExpr {
97124
DelegateCall dc;
98125

99-
DelegateCallExpr() { this.getExpr() = dc.getDelegateExpr() }
126+
DelegateCallExpr() { this.getExpr() = dc.getExpr() }
100127

101128
/** Gets the delegate call that this expression belongs to. */
102-
DelegateCall getDelegateCall() { result = dc }
129+
override DelegateCall getCall() { result = dc }
130+
}
131+
132+
/** A function pointer call expression. */
133+
class FunctionPointerCallExpr extends DelegateLikeCallExpr {
134+
FunctionPointerCall fptrc;
135+
136+
FunctionPointerCallExpr() { this.getExpr() = fptrc.getExpr() }
137+
138+
/** Gets the function pointer call that this expression belongs to. */
139+
override FunctionPointerCall getCall() { result = fptrc }
103140
}
104141

105142
/** A parameter of delegate type belonging to a callable with a flow summary. */
106-
class SummaryDelegateParameterSink extends DelegateFlowSink, ParameterNode {
143+
class SummaryDelegateParameterSink extends DelegateLikeFlowSink, ParameterNode {
107144
SummaryDelegateParameterSink() {
108145
this.getType() instanceof SystemLinqExpressions::DelegateExtType and
109146
this.isParameterOf(any(SummarizedCallable c), _)
110147
}
111148
}
112149

113150
/** A delegate expression that is added to an event. */
114-
class AddEventSource extends DelegateFlowSink, DataFlow::ExprNode {
151+
class AddEventSource extends DelegateLikeFlowSink, DataFlow::ExprNode {
115152
AddEventExpr ae;
116153

117154
AddEventSource() { this.getExpr() = ae.getRValue() }
@@ -150,7 +187,7 @@ private class NormalReturnNode extends Node {
150187
* records the last call on the path from `node` to `sink`, if any.
151188
*/
152189
private predicate flowsFrom(
153-
DelegateFlowSink sink, DataFlow::Node node, boolean isReturned, CallContext lastCall
190+
DelegateLikeFlowSink sink, DataFlow::Node node, boolean isReturned, CallContext lastCall
154191
) {
155192
// Base case
156193
sink = node and
@@ -188,7 +225,8 @@ private predicate flowsFrom(
188225
or
189226
// Flow into a callable (delegate call)
190227
exists(
191-
ParameterNode mid, CallContext prevLastCall, DelegateCall call, Callable c, Parameter p, int i
228+
ParameterNode mid, CallContext prevLastCall, DelegateLikeCall call, Callable c, Parameter p,
229+
int i
192230
|
193231
flowsFrom(sink, mid, isReturned, prevLastCall) and
194232
isReturned = false and
@@ -238,14 +276,14 @@ private predicate flowIntoNonDelegateCall(NonDelegateCall call, Expr arg, DotNet
238276
}
239277

240278
pragma[noinline]
241-
private predicate flowIntoDelegateCall(DelegateCall call, Callable c, Expr arg, int i) {
242-
exists(DelegateFlowSource dfs, DelegateCallExpr dce |
279+
private predicate flowIntoDelegateCall(DelegateLikeCall call, Callable c, Expr arg, int i) {
280+
exists(DelegateLikeFlowSource dfs, DelegateLikeCallExpr dce |
243281
// the call context is irrelevant because the delegate call
244282
// itself will be the context
245283
flowsFrom(dce, dfs, _, _) and
246284
arg = call.getArgument(i) and
247285
c = dfs.getCallable() and
248-
call = dce.getDelegateCall()
286+
call = dce.getCall()
249287
)
250288
}
251289

@@ -255,11 +293,13 @@ private predicate flowOutOfNonDelegateCall(NonDelegateCall call, NormalReturnNod
255293
}
256294

257295
pragma[noinline]
258-
private predicate flowOutOfDelegateCall(DelegateCall dc, NormalReturnNode ret, CallContext lastCall) {
259-
exists(DelegateFlowSource dfs, DelegateCallExpr dce, Callable c |
296+
private predicate flowOutOfDelegateCall(
297+
DelegateLikeCall dc, NormalReturnNode ret, CallContext lastCall
298+
) {
299+
exists(DelegateLikeFlowSource dfs, DelegateLikeCallExpr dce, Callable c |
260300
flowsFrom(dce, dfs, _, lastCall) and
261301
ret.getEnclosingCallable() = c and
262302
c = dfs.getCallable() and
263-
dc = dce.getDelegateCall()
303+
dc = dce.getCall()
264304
)
265305
}

0 commit comments

Comments
 (0)