Skip to content

Commit 58fe81d

Browse files
authored
Merge pull request #5455 from hvitved/dataflow/lambda-doc
Data flow: Add section on lambda flow to `dataflow.md`
2 parents a889316 + 98558c7 commit 58fe81d

File tree

1 file changed

+39
-0
lines changed

1 file changed

+39
-0
lines changed

docs/ql-libraries/dataflow/dataflow.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,45 @@ values, for example through `out` parameters in C#, the `ReturnKind` class can
186186
be defined and used to match up different kinds of `ReturnNode`s with the
187187
corresponding `OutNode`s.
188188

189+
#### First-class functions
190+
191+
For calls to first-class functions, the library supports built-in call resolution based on data flow between a function creation expression and a call. The interface that needs to be implemented is
192+
193+
```ql
194+
class LambdaCallKind
195+
196+
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
197+
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c)
198+
199+
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
200+
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver)
201+
202+
/** Extra data-flow steps needed for lambda flow analysis. */
203+
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue)
204+
```
205+
206+
with the semantics that `call` will resolve to `c` if there is a data-flow path from `creation` to `receiver`, with matching `kind`s.
207+
208+
The implementation keeps track of a one-level call context, which means that we are able to handle situations like this:
209+
```csharp
210+
Apply(f, x) { f(x); }
211+
212+
Apply(x => NonSink(x), "tainted"); // GOOD
213+
214+
Apply(x => Sink(x), "not tainted"); // GOOD
215+
```
216+
217+
However, since we only track one level the following example will have false-positive flow:
218+
```csharp
219+
Apply(f, x) { f(x); }
220+
221+
ApplyWrapper(f, x) { Apply(f, x) }
222+
223+
ApplyWrapper(x => NonSink(x), "tainted"); // GOOD (FALSE POSITIVE)
224+
225+
ApplyWrapper(x => Sink(x), "not tainted"); // GOOD (FALSE POSITIVE)
226+
```
227+
189228
## Flow through global variables
190229

191230
Flow through global variables are called jump-steps, since such flow steps

0 commit comments

Comments
 (0)