Skip to content

Commit 4fa22b9

Browse files
authored
Merge pull request #22637 from github/rust/async-block-lambda
Rust: Make await call async blocks as lambdas in dataflow
2 parents ac07464 + b05fb21 commit 4fa22b9

9 files changed

Lines changed: 270 additions & 5 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Improve data flow for async blocks when used with `await`.

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ final class DataFlowCall extends TDataFlowCall {
6262
/** Gets the underlying call, if any. */
6363
Call asCall() { this = TCall(result) }
6464

65+
/** Gets the underlying await expression, if any. */
66+
AwaitExpr asAwaitExpr() { this = TAwaitExpr(result) }
67+
6568
predicate isImplicitDerefCall(Expr e, DerefChain derefChain, int i, Function target) {
6669
this = TImplicitDerefCall(e, derefChain, i, target)
6770
}
@@ -73,15 +76,16 @@ final class DataFlowCall extends TDataFlowCall {
7376
}
7477

7578
DataFlowCallable getEnclosingCallable() {
76-
result.asCfgScope() = this.asCall().getEnclosingCfgScope()
79+
result.asCfgScope() =
80+
[this.asCall().getEnclosingCfgScope(), this.asAwaitExpr().getEnclosingCfgScope()]
7781
or
7882
result.asCfgScope() = any(Expr e | this.isImplicitDerefCall(e, _, _, _)).getEnclosingCfgScope()
7983
or
8084
this.isSummaryCall(result.asSummarizedCallable(), _)
8185
}
8286

8387
string toString() {
84-
result = this.asCall().toString()
88+
result = [this.asCall().toString(), this.asAwaitExpr().toString()]
8589
or
8690
exists(Expr e, DerefChain derefChain, int i |
8791
this.isImplicitDerefCall(e, derefChain, i, _) and
@@ -97,7 +101,7 @@ final class DataFlowCall extends TDataFlowCall {
97101
}
98102

99103
Location getLocation() {
100-
result = this.asCall().getLocation()
104+
result = [this.asCall().getLocation(), this.asAwaitExpr().getLocation()]
101105
or
102106
result = any(Expr e | this.isImplicitDerefCall(e, _, _, _)).getLocation()
103107
}
@@ -1004,7 +1008,11 @@ module RustDataFlowGen<RustDataFlowInputSig Input> implements InputSig<Location>
10041008
*/
10051009
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
10061010
(
1007-
receiver.asExpr() = call.asCall().(CallExprImpl::DynamicCallExpr).getFunction()
1011+
receiver.asExpr() =
1012+
[
1013+
call.asCall().(CallExprImpl::DynamicCallExpr).getFunction(),
1014+
call.asAwaitExpr().getExpr()
1015+
]
10081016
or
10091017
call.isSummaryCall(_, receiver.(FlowSummaryNode).getSummaryNode())
10101018
) and
@@ -1176,6 +1184,7 @@ private module Cached {
11761184
Stages::DataFlowStage::ref() and
11771185
call.hasEnclosingCfgScope()
11781186
} or
1187+
TAwaitExpr(AwaitExpr await) { await.hasEnclosingCfgScope() } or
11791188
TImplicitDerefCall(Expr e, DerefChain derefChain, int i, Function target) {
11801189
TypeInference::implicitDerefChainBorrow(e, derefChain, _) and
11811190
target = derefChain.getElement(i).getDerefFunction() and

‎rust/ql/lib/codeql/rust/dataflow/internal/Node.qll‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,20 @@ final class ClosureArgumentNode extends ArgumentNode, ExprNode {
435435
}
436436
}
437437

438+
/**
439+
* A data flow node that represents the run-time representation of an async
440+
* block passed into its body when awaited.
441+
*/
442+
final class AsyncBlockArgumentNode extends ArgumentNode, ExprNode {
443+
private AwaitExpr await;
444+
445+
AsyncBlockArgumentNode() { this.asExpr() = await.getExpr() }
446+
447+
override predicate isArgumentOf(DataFlowCall call, RustDataFlow::ArgumentPosition pos) {
448+
call.asAwaitExpr() = await and pos.isClosureSelf()
449+
}
450+
}
451+
438452
/** An SSA node. */
439453
class SsaNode extends Node, TSsaNode {
440454
SsaImpl::DataFlowIntegration::SsaNode node;
@@ -485,12 +499,17 @@ final private class ExprOutNode extends ExprNode, OutNode {
485499
not call instanceof DerefExpr and // Handled by `DerefOutNode`
486500
not call instanceof IndexExpr // Handled by `IndexOutNode`
487501
)
502+
or
503+
this.asExpr() instanceof AwaitExpr
488504
}
489505

490506
/** Gets the underlying call node that includes this out node. */
491507
override DataFlowCall getCall(ReturnKind kind) {
492508
result.asCall() = n and
493509
kind = TNormalReturnKind()
510+
or
511+
result.asAwaitExpr() = n and
512+
kind = TNormalReturnKind()
494513
}
495514
}
496515

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,9 @@ edges
196196
| main.rs:342:9:342:9 | a | main.rs:343:10:343:10 | a | provenance | |
197197
| main.rs:342:13:342:26 | async_source(...) | main.rs:342:9:342:9 | a | provenance | |
198198
| main.rs:346:13:346:13 | c | main.rs:347:14:347:14 | c | provenance | |
199+
| main.rs:346:13:346:13 | c | main.rs:348:9:348:9 | c | provenance | |
199200
| main.rs:346:17:346:25 | source(...) | main.rs:346:13:346:13 | c | provenance | |
201+
| main.rs:348:9:348:9 | c | main.rs:350:10:350:16 | await b | provenance | |
200202
| main.rs:354:9:354:9 | a | main.rs:355:10:355:10 | a | provenance | |
201203
| main.rs:354:13:354:55 | ...::block_on(...) | main.rs:354:9:354:9 | a | provenance | |
202204
| main.rs:354:41:354:54 | async_source(...) | main.rs:354:13:354:55 | ...::block_on(...) | provenance | MaD:3 |
@@ -443,6 +445,8 @@ nodes
443445
| main.rs:346:13:346:13 | c | semmle.label | c |
444446
| main.rs:346:17:346:25 | source(...) | semmle.label | source(...) |
445447
| main.rs:347:14:347:14 | c | semmle.label | c |
448+
| main.rs:348:9:348:9 | c | semmle.label | c |
449+
| main.rs:350:10:350:16 | await b | semmle.label | await b |
446450
| main.rs:354:9:354:9 | a | semmle.label | a |
447451
| main.rs:354:13:354:55 | ...::block_on(...) | semmle.label | ...::block_on(...) |
448452
| main.rs:354:41:354:54 | async_source(...) | semmle.label | async_source(...) |
@@ -539,6 +543,7 @@ testFailures
539543
| main.rs:337:10:337:10 | a | main.rs:336:13:336:21 | source(...) | main.rs:337:10:337:10 | a | $@ | main.rs:336:13:336:21 | source(...) | source(...) |
540544
| main.rs:343:10:343:10 | a | main.rs:336:13:336:21 | source(...) | main.rs:343:10:343:10 | a | $@ | main.rs:336:13:336:21 | source(...) | source(...) |
541545
| main.rs:347:14:347:14 | c | main.rs:346:17:346:25 | source(...) | main.rs:347:14:347:14 | c | $@ | main.rs:346:17:346:25 | source(...) | source(...) |
546+
| main.rs:350:10:350:16 | await b | main.rs:346:17:346:25 | source(...) | main.rs:350:10:350:16 | await b | $@ | main.rs:346:17:346:25 | source(...) | source(...) |
542547
| main.rs:355:10:355:10 | a | main.rs:336:13:336:21 | source(...) | main.rs:355:10:355:10 | a | $@ | main.rs:336:13:336:21 | source(...) | source(...) |
543548
| main.rs:404:14:404:15 | n1 | main.rs:379:13:379:21 | source(...) | main.rs:404:14:404:15 | n1 | $@ | main.rs:379:13:379:21 | source(...) | source(...) |
544549
| main.rs:408:14:408:15 | n2 | main.rs:379:13:379:21 | source(...) | main.rs:408:14:408:15 | n2 | $@ | main.rs:379:13:379:21 | source(...) | source(...) |

‎rust/ql/test/library-tests/dataflow/global/main.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ async fn test_async_await_async_part() {
347347
sink(c); // $ hasValueFlow=2
348348
c
349349
};
350-
sink(b.await); // $ MISSING: hasValueFlow=2
350+
sink(b.await); // $ hasValueFlow=2
351351
}
352352

353353
fn test_async_await() {

‎rust/ql/test/library-tests/dataflow/lambdas/Cargo.lock‎

Lines changed: 144 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ edges
6363
| main.rs:111:26:111:36 | \|...\| ... : ... => .. [captured a] | main.rs:111:35:111:35 | a | provenance | heuristic-callback |
6464
| main.rs:112:26:112:36 | \|...\| ... : ... => .. [captured a] | main.rs:112:35:112:35 | a | provenance | heuristic-callback |
6565
| main.rs:113:26:113:36 | \|...\| ... : ... => .. [captured a] | main.rs:113:35:113:35 | a | provenance | heuristic-callback |
66+
| main.rs:120:30:120:40 | source(...) | main.rs:121:14:121:25 | await future | provenance | |
67+
| main.rs:125:20:125:30 | source(...) | main.rs:126:9:128:9 | { ... } : ... => .. [captured data] | provenance | |
68+
| main.rs:126:9:128:9 | { ... } : ... => .. [captured data] | main.rs:127:18:127:21 | data | provenance | |
69+
| main.rs:133:20:133:30 | source(...) | main.rs:135:14:135:19 | future [captured data] | provenance | |
70+
| main.rs:135:14:135:19 | future [captured data] | main.rs:134:30:134:33 | data | provenance | |
71+
| main.rs:135:14:135:19 | future [captured data] | main.rs:135:14:135:25 | await future | provenance | |
72+
| main.rs:141:9:143:9 | [post] { ... } : ... => .. [captured captured] | main.rs:145:14:145:21 | captured | provenance | |
73+
| main.rs:142:24:142:34 | source(...) | main.rs:141:9:143:9 | [post] { ... } : ... => .. [captured captured] | provenance | |
6674
nodes
6775
| main.rs:10:20:10:52 | if cond {...} else {...} | semmle.label | if cond {...} else {...} |
6876
| main.rs:10:30:10:39 | source(...) | semmle.label | source(...) |
@@ -138,9 +146,22 @@ nodes
138146
| main.rs:112:35:112:35 | a | semmle.label | a |
139147
| main.rs:113:26:113:36 | \|...\| ... : ... => .. [captured a] | semmle.label | \|...\| ... : ... => .. [captured a] |
140148
| main.rs:113:35:113:35 | a | semmle.label | a |
149+
| main.rs:120:30:120:40 | source(...) | semmle.label | source(...) |
150+
| main.rs:121:14:121:25 | await future | semmle.label | await future |
151+
| main.rs:125:20:125:30 | source(...) | semmle.label | source(...) |
152+
| main.rs:126:9:128:9 | { ... } : ... => .. [captured data] | semmle.label | { ... } : ... => .. [captured data] |
153+
| main.rs:127:18:127:21 | data | semmle.label | data |
154+
| main.rs:133:20:133:30 | source(...) | semmle.label | source(...) |
155+
| main.rs:134:30:134:33 | data | semmle.label | data |
156+
| main.rs:135:14:135:19 | future [captured data] | semmle.label | future [captured data] |
157+
| main.rs:135:14:135:25 | await future | semmle.label | await future |
158+
| main.rs:141:9:143:9 | [post] { ... } : ... => .. [captured captured] | semmle.label | [post] { ... } : ... => .. [captured captured] |
159+
| main.rs:142:24:142:34 | source(...) | semmle.label | source(...) |
160+
| main.rs:145:14:145:21 | captured | semmle.label | captured |
141161
subpaths
142162
| main.rs:29:21:29:21 | a | main.rs:27:20:27:23 | ... | main.rs:27:26:27:52 | if cond {...} else {...} | main.rs:29:13:29:22 | f(...) |
143163
| main.rs:77:21:77:21 | a | main.rs:66:24:66:32 | ...: i64 | main.rs:66:42:72:1 | { ... } | main.rs:77:13:77:22 | f(...) |
164+
| main.rs:135:14:135:19 | future [captured data] | main.rs:134:30:134:33 | data | main.rs:134:30:134:33 | data | main.rs:135:14:135:25 | await future |
144165
testFailures
145166
#select
146167
| main.rs:11:10:11:16 | f(...) | main.rs:10:30:10:39 | source(...) | main.rs:11:10:11:16 | f(...) | $@ | main.rs:10:30:10:39 | source(...) | source(...) |
@@ -161,3 +182,7 @@ testFailures
161182
| main.rs:111:35:111:35 | a | main.rs:109:13:109:22 | source(...) | main.rs:111:35:111:35 | a | $@ | main.rs:109:13:109:22 | source(...) | source(...) |
162183
| main.rs:112:35:112:35 | a | main.rs:109:13:109:22 | source(...) | main.rs:112:35:112:35 | a | $@ | main.rs:109:13:109:22 | source(...) | source(...) |
163184
| main.rs:113:35:113:35 | a | main.rs:109:13:109:22 | source(...) | main.rs:113:35:113:35 | a | $@ | main.rs:109:13:109:22 | source(...) | source(...) |
185+
| main.rs:121:14:121:25 | await future | main.rs:120:30:120:40 | source(...) | main.rs:121:14:121:25 | await future | $@ | main.rs:120:30:120:40 | source(...) | source(...) |
186+
| main.rs:127:18:127:21 | data | main.rs:125:20:125:30 | source(...) | main.rs:127:18:127:21 | data | $@ | main.rs:125:20:125:30 | source(...) | source(...) |
187+
| main.rs:135:14:135:25 | await future | main.rs:133:20:133:30 | source(...) | main.rs:135:14:135:25 | await future | $@ | main.rs:133:20:133:30 | source(...) | source(...) |
188+
| main.rs:145:14:145:21 | captured | main.rs:142:24:142:34 | source(...) | main.rs:145:14:145:21 | captured | $@ | main.rs:142:24:142:34 | source(...) | source(...) |

0 commit comments

Comments
 (0)