C#: Add read and store steps for delegate calls. · github/codeql@fe85481 · GitHub
Skip to content

Commit fe85481

Browse files
committed
C#: Add read and store steps for delegate calls.
1 parent ff80b24 commit fe85481

4 files changed

Lines changed: 181 additions & 6 deletions

File tree

‎csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll‎

Lines changed: 86 additions & 2 deletions

‎csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ private import DataFlowDispatch
33
private import DataFlowPrivate
44
private import semmle.code.csharp.controlflow.Guards
55
private import semmle.code.csharp.Unification
6+
private import semmle.code.csharp.frameworks.system.linq.Expressions
67

78
/**
89
* An element, viewed as a node in a data flow graph. Either an expression
@@ -238,6 +239,61 @@ class PropertyContent extends Content, TPropertyContent {
238239
override Location getLocation() { result = p.getLocation() }
239240
}
240241

242+
/**
243+
* A reference to the index of an argument of a delegate call
244+
* (where the delegate is a parameter)
245+
*/
246+
class DelegateCallArgumentContent extends Content, TDelegateCallArgumentContent {
247+
private Parameter p;
248+
private int i;
249+
250+
DelegateCallArgumentContent() { this = TDelegateCallArgumentContent(p, i) }
251+
252+
/** Gets the underlying parameter. */
253+
Parameter getParameter() { result = p }
254+
255+
/**
256+
* Gets the type of the `i`th parameter of the underlying parameter `p`
257+
* (which is of delegate type).
258+
*/
259+
Type getType() {
260+
result =
261+
p.getType()
262+
.(SystemLinqExpressions::DelegateExtType)
263+
.getDelegateType()
264+
.getParameter(i)
265+
.getType()
266+
}
267+
268+
override string toString() { result = "delegate parameter " + p.getName() + " at position " + i }
269+
270+
override Location getLocation() { result = p.getLocation() }
271+
}
272+
273+
/**
274+
* A reference to the return of a delegate call
275+
* (where the delegate is a parameter)
276+
*/
277+
class DelegateCallReturnContent extends Content, TDelegateCallReturnContent {
278+
private Parameter p;
279+
280+
DelegateCallReturnContent() { this = TDelegateCallReturnContent(p) }
281+
282+
/** Gets the underlying parameter. */
283+
Parameter getParameter() { result = p }
284+
285+
/**
286+
* Gets the return type of the underlying parameter `p` (which is of delegate type).
287+
*/
288+
Type getType() {
289+
result = p.getType().(SystemLinqExpressions::DelegateExtType).getDelegateType().getReturnType()
290+
}
291+
292+
override string toString() { result = "delegate parameter " + p.getName() + " result" }
293+
294+
override Location getLocation() { result = p.getLocation() }
295+
}
296+
241297
/**
242298
* A reference to a synthetic field corresponding to a
243299
* primary constructor parameter.
@@ -299,6 +355,20 @@ class ContentSet extends TContentSet {
299355
*/
300356
predicate isProperty(Property p) { this = TPropertyContentSet(p) }
301357

358+
/**
359+
* Holds if this content set represents the `i`th argument of
360+
* the parameter `p` of delegate type in a delegate call.
361+
*/
362+
predicate isDelegateCallArgument(Parameter p, int i) {
363+
this.isSingleton(TDelegateCallArgumentContent(p, i))
364+
}
365+
366+
/**
367+
* Holds if this content set represents the return of a delegate call
368+
* of parameter `p` (which is of delegate type).
369+
*/
370+
predicate isDelegateCallReturn(Parameter p) { this.isSingleton(TDelegateCallReturnContent(p)) }
371+
302372
/** Holds if this content set represents the field `f`. */
303373
predicate isField(Field f) { this.isSingleton(TFieldContent(f)) }
304374

‎csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,9 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CsharpDat
101101
api = any(FlowSummaryImpl::Public::NeutralSinkCallable sc | sc.hasManualModel())
102102
}
103103

104-
predicate isUninterestingForDataFlowModels(Callable api) { isHigherOrder(api) }
104+
predicate isUninterestingForDataFlowModels(Callable api) { none() }
105+
106+
predicate isUninterestingForHeuristicDataFlowModels(Callable api) { isHigherOrder(api) }
105107

106108
class SourceOrSinkTargetApi extends Callable {
107109
SourceOrSinkTargetApi() { relevant(this) }
@@ -175,7 +177,9 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CsharpDat
175177
*/
176178
private CS::Type getUnderlyingContType(DataFlow::Content c) {
177179
result = c.(DataFlow::FieldContent).getField().getType() or
178-
result = c.(DataFlow::SyntheticFieldContent).getField().getType()
180+
result = c.(DataFlow::SyntheticFieldContent).getField().getType() or
181+
result = c.(DataFlow::DelegateCallArgumentContent).getType() or
182+
result = c.(DataFlow::DelegateCallReturnContent).getType()
179183
}
180184

181185
Type getUnderlyingContentType(DataFlow::ContentSet c) {
@@ -342,6 +346,10 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CsharpDat
342346
or
343347
c.isElement() and
344348
result = "Element"
349+
or
350+
exists(int i | c.isDelegateCallArgument(_, i) and result = "Parameter[" + i + "]")
351+
or
352+
c.isDelegateCallReturn(_) and result = "ReturnValue"
345353
}
346354

347355
predicate partialModel = ExternalFlow::partialModel/6;

‎shared/mad/codeql/mad/modelgenerator/internal/ModelGeneratorImpl.qll‎

Lines changed: 15 additions & 2 deletions

0 commit comments

Comments
 (0)