Skip to content

Commit 4371433

Browse files
authored
Merge pull request github#18160 from paldepind/rust-df-closure
Rust: Handle closures/lambdas in data flow
2 parents 7463c51 + 33fe51d commit 4371433

File tree

4 files changed

+126
-6
lines changed

4 files changed

+126
-6
lines changed

rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,14 +1020,29 @@ module RustDataFlow implements InputSig<Location> {
10201020
.getSummaryNode(), node2.(Node::FlowSummaryNode).getSummaryNode())
10211021
}
10221022

1023-
class LambdaCallKind = Void;
1023+
class LambdaCallKind = Unit;
10241024

1025-
// class LambdaCallKind;
10261025
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
1027-
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { none() }
1026+
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) {
1027+
exists(ClosureExpr cl |
1028+
cl = creation.asExpr().getExpr() and
1029+
cl = c.asCfgScope()
1030+
) and
1031+
exists(kind)
1032+
}
10281033

1029-
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
1030-
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { none() }
1034+
/**
1035+
* Holds if `call` is a lambda call of kind `kind` where `receiver` is the
1036+
* invoked expression.
1037+
*/
1038+
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
1039+
receiver.asExpr() = call.asCallExprCfgNode().getFunction() and
1040+
// All calls to complex expressions and local variable accesses are lambda call.
1041+
exists(Expr f | f = receiver.asExpr().getExpr() |
1042+
f instanceof PathExpr implies f = any(Variable v).getAnAccess()
1043+
) and
1044+
exists(kind)
1045+
}
10311046

10321047
/** Extra data flow steps needed for lambda flow analysis. */
10331048
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }

rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,50 @@ localStep
344344
| main.rs:306:22:306:22 | [SSA] n | main.rs:306:34:306:34 | n |
345345
| main.rs:306:22:306:22 | n | main.rs:306:22:306:22 | [SSA] n |
346346
| main.rs:306:29:306:35 | sink(...) | main.rs:304:5:307:5 | match s2 { ... } |
347+
| main.rs:314:9:314:9 | [SSA] f | main.rs:315:10:315:10 | f |
348+
| main.rs:314:9:314:9 | f | main.rs:314:9:314:9 | [SSA] f |
349+
| main.rs:314:13:314:52 | \|...\| ... | main.rs:314:9:314:9 | f |
350+
| main.rs:314:14:314:17 | ... | main.rs:314:14:314:17 | cond |
351+
| main.rs:314:14:314:17 | [SSA] cond | main.rs:314:23:314:26 | cond |
352+
| main.rs:314:14:314:17 | cond | main.rs:314:14:314:17 | [SSA] cond |
353+
| main.rs:314:28:314:41 | { ... } | main.rs:314:20:314:52 | if cond {...} else {...} |
354+
| main.rs:314:30:314:39 | source(...) | main.rs:314:28:314:41 | { ... } |
355+
| main.rs:314:48:314:52 | { ... } | main.rs:314:20:314:52 | if cond {...} else {...} |
356+
| main.rs:314:50:314:50 | 0 | main.rs:314:48:314:52 | { ... } |
357+
| main.rs:319:9:319:9 | [SSA] f | main.rs:326:5:326:5 | f |
358+
| main.rs:319:9:319:9 | f | main.rs:319:9:319:9 | [SSA] f |
359+
| main.rs:319:13:324:9 | \|...\| ... | main.rs:319:9:319:9 | f |
360+
| main.rs:319:14:319:17 | ... | main.rs:319:14:319:17 | cond |
361+
| main.rs:319:14:319:17 | [SSA] cond | main.rs:320:12:320:15 | cond |
362+
| main.rs:319:14:319:17 | cond | main.rs:319:14:319:17 | [SSA] cond |
363+
| main.rs:319:20:319:23 | ... | main.rs:319:20:319:23 | data |
364+
| main.rs:319:20:319:23 | [SSA] data | main.rs:321:18:321:21 | data |
365+
| main.rs:319:20:319:23 | data | main.rs:319:20:319:23 | [SSA] data |
366+
| main.rs:320:17:322:9 | { ... } | main.rs:320:9:324:9 | if cond {...} else {...} |
367+
| main.rs:322:16:324:9 | { ... } | main.rs:320:9:324:9 | if cond {...} else {...} |
368+
| main.rs:323:13:323:19 | sink(...) | main.rs:322:16:324:9 | { ... } |
369+
| main.rs:325:9:325:9 | [SSA] a | main.rs:326:13:326:13 | a |
370+
| main.rs:325:9:325:9 | a | main.rs:325:9:325:9 | [SSA] a |
371+
| main.rs:325:13:325:22 | source(...) | main.rs:325:9:325:9 | a |
372+
| main.rs:330:9:330:9 | [SSA] f | main.rs:337:13:337:13 | f |
373+
| main.rs:330:9:330:9 | f | main.rs:330:9:330:9 | [SSA] f |
374+
| main.rs:330:13:335:9 | \|...\| ... | main.rs:330:9:330:9 | f |
375+
| main.rs:330:14:330:17 | ... | main.rs:330:14:330:17 | cond |
376+
| main.rs:330:14:330:17 | [SSA] cond | main.rs:331:12:331:15 | cond |
377+
| main.rs:330:14:330:17 | cond | main.rs:330:14:330:17 | [SSA] cond |
378+
| main.rs:330:20:330:23 | ... | main.rs:330:20:330:23 | data |
379+
| main.rs:330:20:330:23 | [SSA] data | main.rs:332:13:332:16 | data |
380+
| main.rs:330:20:330:23 | data | main.rs:330:20:330:23 | [SSA] data |
381+
| main.rs:331:17:333:9 | { ... } | main.rs:331:9:335:9 | if cond {...} else {...} |
382+
| main.rs:332:13:332:16 | data | main.rs:331:17:333:9 | { ... } |
383+
| main.rs:333:16:335:9 | { ... } | main.rs:331:9:335:9 | if cond {...} else {...} |
384+
| main.rs:334:13:334:13 | 0 | main.rs:333:16:335:9 | { ... } |
385+
| main.rs:336:9:336:9 | [SSA] a | main.rs:337:21:337:21 | a |
386+
| main.rs:336:9:336:9 | a | main.rs:336:9:336:9 | [SSA] a |
387+
| main.rs:336:13:336:22 | source(...) | main.rs:336:9:336:9 | a |
388+
| main.rs:337:9:337:9 | [SSA] b | main.rs:338:10:338:10 | b |
389+
| main.rs:337:9:337:9 | b | main.rs:337:9:337:9 | [SSA] b |
390+
| main.rs:337:13:337:22 | f(...) | main.rs:337:9:337:9 | b |
347391
storeStep
348392
| main.rs:94:14:94:22 | source(...) | tuple.0 | main.rs:94:13:94:26 | TupleExpr |
349393
| main.rs:94:25:94:25 | 2 | tuple.1 | main.rs:94:13:94:26 | TupleExpr |
@@ -385,7 +429,7 @@ storeStep
385429
| main.rs:276:41:276:41 | 2 | D | main.rs:276:14:276:43 | ...::D {...} |
386430
| main.rs:294:18:294:27 | source(...) | C | main.rs:293:14:295:5 | C {...} |
387431
| main.rs:296:27:296:27 | 2 | D | main.rs:296:14:296:29 | D {...} |
388-
| main.rs:314:27:314:27 | 0 | Some | main.rs:314:22:314:28 | Some(...) |
432+
| main.rs:345:27:345:27 | 0 | Some | main.rs:345:22:345:28 | Some(...) |
389433
readStep
390434
| file://:0:0:0:0 | [summary param] self in lang:core::_::<crate::option::Option>::unwrap | Some | file://:0:0:0:0 | [summary] read: Argument[self].Variant[crate::option::Option::Some(0)] in lang:core::_::<crate::option::Option>::unwrap |
391435
| main.rs:33:9:33:15 | TupleStructPat | Some | main.rs:33:14:33:14 | _ |

rust/ql/test/library-tests/dataflow/local/inline-flow.expected

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,16 @@ edges
6464
| main.rs:298:22:298:22 | n | main.rs:298:34:298:34 | n | provenance | |
6565
| main.rs:302:9:302:24 | C {...} [C] | main.rs:302:22:302:22 | n | provenance | |
6666
| main.rs:302:22:302:22 | n | main.rs:302:53:302:53 | n | provenance | |
67+
| main.rs:314:20:314:52 | if cond {...} else {...} | main.rs:315:10:315:16 | f(...) | provenance | |
68+
| main.rs:314:30:314:39 | source(...) | main.rs:314:20:314:52 | if cond {...} else {...} | provenance | |
69+
| main.rs:319:20:319:23 | ... | main.rs:321:18:321:21 | data | provenance | |
70+
| main.rs:325:13:325:22 | source(...) | main.rs:326:13:326:13 | a | provenance | |
71+
| main.rs:326:13:326:13 | a | main.rs:319:20:319:23 | ... | provenance | |
72+
| main.rs:330:20:330:23 | ... | main.rs:331:9:335:9 | if cond {...} else {...} | provenance | |
73+
| main.rs:336:13:336:22 | source(...) | main.rs:337:21:337:21 | a | provenance | |
74+
| main.rs:337:13:337:22 | f(...) | main.rs:338:10:338:10 | b | provenance | |
75+
| main.rs:337:21:337:21 | a | main.rs:330:20:330:23 | ... | provenance | |
76+
| main.rs:337:21:337:21 | a | main.rs:337:13:337:22 | f(...) | provenance | |
6777
nodes
6878
| main.rs:15:10:15:18 | source(...) | semmle.label | source(...) |
6979
| main.rs:19:13:19:21 | source(...) | semmle.label | source(...) |
@@ -147,7 +157,21 @@ nodes
147157
| main.rs:302:9:302:24 | C {...} [C] | semmle.label | C {...} [C] |
148158
| main.rs:302:22:302:22 | n | semmle.label | n |
149159
| main.rs:302:53:302:53 | n | semmle.label | n |
160+
| main.rs:314:20:314:52 | if cond {...} else {...} | semmle.label | if cond {...} else {...} |
161+
| main.rs:314:30:314:39 | source(...) | semmle.label | source(...) |
162+
| main.rs:315:10:315:16 | f(...) | semmle.label | f(...) |
163+
| main.rs:319:20:319:23 | ... | semmle.label | ... |
164+
| main.rs:321:18:321:21 | data | semmle.label | data |
165+
| main.rs:325:13:325:22 | source(...) | semmle.label | source(...) |
166+
| main.rs:326:13:326:13 | a | semmle.label | a |
167+
| main.rs:330:20:330:23 | ... | semmle.label | ... |
168+
| main.rs:331:9:335:9 | if cond {...} else {...} | semmle.label | if cond {...} else {...} |
169+
| main.rs:336:13:336:22 | source(...) | semmle.label | source(...) |
170+
| main.rs:337:13:337:22 | f(...) | semmle.label | f(...) |
171+
| main.rs:337:21:337:21 | a | semmle.label | a |
172+
| main.rs:338:10:338:10 | b | semmle.label | b |
150173
subpaths
174+
| main.rs:337:21:337:21 | a | main.rs:330:20:330:23 | ... | main.rs:331:9:335:9 | if cond {...} else {...} | main.rs:337:13:337:22 | f(...) |
151175
testFailures
152176
#select
153177
| main.rs:15:10:15:18 | source(...) | main.rs:15:10:15:18 | source(...) | main.rs:15:10:15:18 | source(...) | $@ | main.rs:15:10:15:18 | source(...) | source(...) |
@@ -172,3 +196,6 @@ testFailures
172196
| main.rs:282:81:282:81 | n | main.rs:274:18:274:27 | source(...) | main.rs:282:81:282:81 | n | $@ | main.rs:274:18:274:27 | source(...) | source(...) |
173197
| main.rs:298:34:298:34 | n | main.rs:294:18:294:27 | source(...) | main.rs:298:34:298:34 | n | $@ | main.rs:294:18:294:27 | source(...) | source(...) |
174198
| main.rs:302:53:302:53 | n | main.rs:294:18:294:27 | source(...) | main.rs:302:53:302:53 | n | $@ | main.rs:294:18:294:27 | source(...) | source(...) |
199+
| main.rs:315:10:315:16 | f(...) | main.rs:314:30:314:39 | source(...) | main.rs:315:10:315:16 | f(...) | $@ | main.rs:314:30:314:39 | source(...) | source(...) |
200+
| main.rs:321:18:321:21 | data | main.rs:325:13:325:22 | source(...) | main.rs:321:18:321:21 | data | $@ | main.rs:325:13:325:22 | source(...) | source(...) |
201+
| main.rs:338:10:338:10 | b | main.rs:336:13:336:22 | source(...) | main.rs:338:10:338:10 | b | $@ | main.rs:336:13:336:22 | source(...) | source(...) |

rust/ql/test/library-tests/dataflow/local/main.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,37 @@ fn custom_record_enum_pattern_match_unqualified() {
307307
}
308308
}
309309

310+
// -----------------------------------------------------------------------------
311+
// Data flow through closures
312+
313+
fn closure_flow_out() {
314+
let f = |cond| if cond { source(92) } else { 0 };
315+
sink(f(true)); // $ hasValueFlow=92
316+
}
317+
318+
fn closure_flow_in() {
319+
let f = |cond, data|
320+
if cond {
321+
sink(data); // $ hasValueFlow=87
322+
} else {
323+
sink(0)
324+
};
325+
let a = source(87);
326+
f(true, a);
327+
}
328+
329+
fn closure_flow_through() {
330+
let f = |cond, data|
331+
if cond {
332+
data
333+
} else {
334+
0
335+
};
336+
let a = source(43);
337+
let b = f(true, a);
338+
sink(b); // $ hasValueFlow=43
339+
}
340+
310341
fn main() {
311342
direct();
312343
variable_usage();
@@ -334,4 +365,7 @@ fn main() {
334365
block_expression1();
335366
block_expression2(true);
336367
block_expression3(true);
368+
closure_flow_out();
369+
closure_flow_in();
370+
closure_flow_through();
337371
}

0 commit comments

Comments
 (0)