Skip to content

Commit 2541e9c

Browse files
committed
C#: Handle async data flow in expression bodied callables
1 parent 048c72a commit 2541e9c

File tree

4 files changed

+29
-19
lines changed

4 files changed

+29
-19
lines changed

csharp/ql/src/semmle/code/csharp/Callable.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ private import dotnet
1111
private import semmle.code.csharp.ExprOrStmtParent
1212
private import semmle.code.csharp.metrics.Complexity
1313
private import TypeRef
14+
private import semmle.code.csharp.frameworks.system.threading.Tasks
1415

1516
/**
1617
* An element that can be called.
@@ -206,7 +207,11 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal
206207
exists(ReturnStmt ret | ret.getEnclosingCallable() = this | e = ret.getExpr())
207208
or
208209
e = this.getExpressionBody() and
209-
not this.getReturnType() instanceof VoidType
210+
not this.getReturnType() instanceof VoidType and
211+
(
212+
not this.(Modifiable).isAsync() or
213+
not this.getReturnType() instanceof SystemThreadingTasksTaskClass
214+
)
210215
}
211216

212217
/** Holds if this callable can yield return the expression `e`. */

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,7 @@ private module Cached {
788788
or
789789
exists(Expr e |
790790
e = node1.asExpr() and
791-
node2.(AsyncReturnNode).getReturnStmt().getExpr() = e and
791+
node2.(AsyncReturnNode).getExpr() = e and
792792
c = getResultContent()
793793
)
794794
or
@@ -1411,23 +1411,23 @@ private module ReturnNodes {
14111411
*/
14121412
class AsyncReturnNode extends ReturnNode, NodeImpl, TAsyncReturnNode {
14131413
private ControlFlow::Nodes::ElementNode cfn;
1414-
private ReturnStmt rs;
1414+
private Expr expr;
14151415

1416-
AsyncReturnNode() { this = TAsyncReturnNode(cfn) and rs.getExpr().getAControlFlowNode() = cfn }
1416+
AsyncReturnNode() { this = TAsyncReturnNode(cfn) and expr = cfn.getElement() }
14171417

1418-
ReturnStmt getReturnStmt() { result = rs }
1418+
Expr getExpr() { result = expr }
14191419

14201420
override NormalReturnKind getKind() { any() }
14211421

1422-
override Callable getEnclosingCallableImpl() { result = rs.getEnclosingCallable() }
1422+
override Callable getEnclosingCallableImpl() { result = expr.getEnclosingCallable() }
14231423

1424-
override Type getTypeImpl() { result = rs.getEnclosingCallable().getReturnType() }
1424+
override Type getTypeImpl() { result = expr.getEnclosingCallable().getReturnType() }
14251425

14261426
override ControlFlow::Node getControlFlowNodeImpl() { result = cfn }
14271427

1428-
override Location getLocationImpl() { result = rs.getLocation() }
1428+
override Location getLocationImpl() { result = expr.getLocation() }
14291429

1430-
override string toStringImpl() { result = rs.toString() }
1430+
override string toStringImpl() { result = expr.toString() }
14311431
}
14321432

14331433
/**

csharp/ql/test/library-tests/dataflow/async/Async.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public async Task TestAwait2(string input)
2929

3030
public void TestAwait3(string input)
3131
{
32-
Sink(ReturnAwait(input).Result);
32+
Sink(ReturnAwait2(input).Result);
3333
}
3434

3535
private async Task<string> ReturnAwait(string x)
@@ -47,4 +47,6 @@ private Task<string> ReturnTask(string x)
4747
{
4848
return Task.FromResult(x);
4949
}
50+
51+
private async Task<string> ReturnAwait2(string x) => x;
5052
}

csharp/ql/test/library-tests/dataflow/async/Async.expected

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,20 @@ edges
1010
| Async.cs:26:17:26:40 | await ... : String | Async.cs:27:14:27:14 | access to local variable x |
1111
| Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String | Async.cs:26:17:26:40 | await ... : String |
1212
| Async.cs:26:35:26:39 | access to parameter input : String | Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String |
13-
| Async.cs:30:35:30:39 | input : String | Async.cs:32:26:32:30 | access to parameter input : String |
14-
| Async.cs:32:14:32:31 | call to method ReturnAwait [Result] : String | Async.cs:32:14:32:38 | access to property Result |
15-
| Async.cs:32:26:32:30 | access to parameter input : String | Async.cs:32:14:32:31 | call to method ReturnAwait [Result] : String |
13+
| Async.cs:30:35:30:39 | input : String | Async.cs:32:27:32:31 | access to parameter input : String |
14+
| Async.cs:32:14:32:32 | call to method ReturnAwait2 [Result] : String | Async.cs:32:14:32:39 | access to property Result |
15+
| Async.cs:32:27:32:31 | access to parameter input : String | Async.cs:32:14:32:32 | call to method ReturnAwait2 [Result] : String |
1616
| Async.cs:35:51:35:51 | x : String | Async.cs:38:16:38:16 | access to parameter x : String |
1717
| Async.cs:38:16:38:16 | access to parameter x : String | Async.cs:21:20:21:37 | call to method ReturnAwait [Result] : String |
1818
| Async.cs:38:16:38:16 | access to parameter x : String | Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String |
19-
| Async.cs:38:16:38:16 | access to parameter x : String | Async.cs:32:14:32:31 | call to method ReturnAwait [Result] : String |
2019
| Async.cs:41:33:41:37 | input : String | Async.cs:43:25:43:29 | access to parameter input : String |
2120
| Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String | Async.cs:43:14:43:37 | access to property Result |
2221
| Async.cs:43:25:43:29 | access to parameter input : String | Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String |
2322
| Async.cs:46:44:46:44 | x : String | Async.cs:48:32:48:32 | access to parameter x : String |
2423
| Async.cs:48:16:48:33 | call to method FromResult [Result] : String | Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String |
2524
| Async.cs:48:32:48:32 | access to parameter x : String | Async.cs:48:16:48:33 | call to method FromResult [Result] : String |
25+
| Async.cs:51:52:51:52 | x : String | Async.cs:51:58:51:58 | access to parameter x : String |
26+
| Async.cs:51:58:51:58 | access to parameter x : String | Async.cs:32:14:32:32 | call to method ReturnAwait2 [Result] : String |
2627
nodes
2728
| Async.cs:9:37:9:41 | input : String | semmle.label | input : String |
2829
| Async.cs:11:14:11:26 | call to method Return | semmle.label | call to method Return |
@@ -39,9 +40,9 @@ nodes
3940
| Async.cs:26:35:26:39 | access to parameter input : String | semmle.label | access to parameter input : String |
4041
| Async.cs:27:14:27:14 | access to local variable x | semmle.label | access to local variable x |
4142
| Async.cs:30:35:30:39 | input : String | semmle.label | input : String |
42-
| Async.cs:32:14:32:31 | call to method ReturnAwait [Result] : String | semmle.label | call to method ReturnAwait [Result] : String |
43-
| Async.cs:32:14:32:38 | access to property Result | semmle.label | access to property Result |
44-
| Async.cs:32:26:32:30 | access to parameter input : String | semmle.label | access to parameter input : String |
43+
| Async.cs:32:14:32:32 | call to method ReturnAwait2 [Result] : String | semmle.label | call to method ReturnAwait2 [Result] : String |
44+
| Async.cs:32:14:32:39 | access to property Result | semmle.label | access to property Result |
45+
| Async.cs:32:27:32:31 | access to parameter input : String | semmle.label | access to parameter input : String |
4546
| Async.cs:35:51:35:51 | x : String | semmle.label | x : String |
4647
| Async.cs:38:16:38:16 | access to parameter x : String | semmle.label | access to parameter x : String |
4748
| Async.cs:41:33:41:37 | input : String | semmle.label | input : String |
@@ -51,14 +52,16 @@ nodes
5152
| Async.cs:46:44:46:44 | x : String | semmle.label | x : String |
5253
| Async.cs:48:16:48:33 | call to method FromResult [Result] : String | semmle.label | call to method FromResult [Result] : String |
5354
| Async.cs:48:32:48:32 | access to parameter x : String | semmle.label | access to parameter x : String |
55+
| Async.cs:51:52:51:52 | x : String | semmle.label | x : String |
56+
| Async.cs:51:58:51:58 | access to parameter x : String | semmle.label | access to parameter x : String |
5457
#select
5558
| Async.cs:11:14:11:26 | call to method Return | Async.cs:9:37:9:41 | input : String | Async.cs:11:14:11:26 | call to method Return | $@ flows to here and is used. | Async.cs:9:37:9:41 | input | User-provided value |
5659
| Async.cs:11:14:11:26 | call to method Return | Async.cs:14:34:14:34 | x : String | Async.cs:11:14:11:26 | call to method Return | $@ flows to here and is used. | Async.cs:14:34:14:34 | x | User-provided value |
5760
| Async.cs:21:14:21:37 | await ... | Async.cs:19:41:19:45 | input : String | Async.cs:21:14:21:37 | await ... | $@ flows to here and is used. | Async.cs:19:41:19:45 | input | User-provided value |
5861
| Async.cs:21:14:21:37 | await ... | Async.cs:35:51:35:51 | x : String | Async.cs:21:14:21:37 | await ... | $@ flows to here and is used. | Async.cs:35:51:35:51 | x | User-provided value |
5962
| Async.cs:27:14:27:14 | access to local variable x | Async.cs:24:41:24:45 | input : String | Async.cs:27:14:27:14 | access to local variable x | $@ flows to here and is used. | Async.cs:24:41:24:45 | input | User-provided value |
6063
| Async.cs:27:14:27:14 | access to local variable x | Async.cs:35:51:35:51 | x : String | Async.cs:27:14:27:14 | access to local variable x | $@ flows to here and is used. | Async.cs:35:51:35:51 | x | User-provided value |
61-
| Async.cs:32:14:32:38 | access to property Result | Async.cs:30:35:30:39 | input : String | Async.cs:32:14:32:38 | access to property Result | $@ flows to here and is used. | Async.cs:30:35:30:39 | input | User-provided value |
62-
| Async.cs:32:14:32:38 | access to property Result | Async.cs:35:51:35:51 | x : String | Async.cs:32:14:32:38 | access to property Result | $@ flows to here and is used. | Async.cs:35:51:35:51 | x | User-provided value |
64+
| Async.cs:32:14:32:39 | access to property Result | Async.cs:30:35:30:39 | input : String | Async.cs:32:14:32:39 | access to property Result | $@ flows to here and is used. | Async.cs:30:35:30:39 | input | User-provided value |
65+
| Async.cs:32:14:32:39 | access to property Result | Async.cs:51:52:51:52 | x : String | Async.cs:32:14:32:39 | access to property Result | $@ flows to here and is used. | Async.cs:51:52:51:52 | x | User-provided value |
6366
| Async.cs:43:14:43:37 | access to property Result | Async.cs:41:33:41:37 | input : String | Async.cs:43:14:43:37 | access to property Result | $@ flows to here and is used. | Async.cs:41:33:41:37 | input | User-provided value |
6467
| Async.cs:43:14:43:37 | access to property Result | Async.cs:46:44:46:44 | x : String | Async.cs:43:14:43:37 | access to property Result | $@ flows to here and is used. | Async.cs:46:44:46:44 | x | User-provided value |

0 commit comments

Comments
 (0)