C#: Handle async data flow in expression bodied callables

This commit is contained in:
Tamas Vajk
2021-03-16 16:32:47 +01:00
parent 048c72a0f2
commit 2541e9cb6a
4 changed files with 29 additions and 19 deletions

View File

@@ -11,6 +11,7 @@ private import dotnet
private import semmle.code.csharp.ExprOrStmtParent
private import semmle.code.csharp.metrics.Complexity
private import TypeRef
private import semmle.code.csharp.frameworks.system.threading.Tasks
/**
* An element that can be called.
@@ -206,7 +207,11 @@ class Callable extends DotNet::Callable, Parameterizable, ExprOrStmtParent, @cal
exists(ReturnStmt ret | ret.getEnclosingCallable() = this | e = ret.getExpr())
or
e = this.getExpressionBody() and
not this.getReturnType() instanceof VoidType
not this.getReturnType() instanceof VoidType and
(
not this.(Modifiable).isAsync() or
not this.getReturnType() instanceof SystemThreadingTasksTaskClass
)
}
/** Holds if this callable can yield return the expression `e`. */

View File

@@ -788,7 +788,7 @@ private module Cached {
or
exists(Expr e |
e = node1.asExpr() and
node2.(AsyncReturnNode).getReturnStmt().getExpr() = e and
node2.(AsyncReturnNode).getExpr() = e and
c = getResultContent()
)
or
@@ -1411,23 +1411,23 @@ private module ReturnNodes {
*/
class AsyncReturnNode extends ReturnNode, NodeImpl, TAsyncReturnNode {
private ControlFlow::Nodes::ElementNode cfn;
private ReturnStmt rs;
private Expr expr;
AsyncReturnNode() { this = TAsyncReturnNode(cfn) and rs.getExpr().getAControlFlowNode() = cfn }
AsyncReturnNode() { this = TAsyncReturnNode(cfn) and expr = cfn.getElement() }
ReturnStmt getReturnStmt() { result = rs }
Expr getExpr() { result = expr }
override NormalReturnKind getKind() { any() }
override Callable getEnclosingCallableImpl() { result = rs.getEnclosingCallable() }
override Callable getEnclosingCallableImpl() { result = expr.getEnclosingCallable() }
override Type getTypeImpl() { result = rs.getEnclosingCallable().getReturnType() }
override Type getTypeImpl() { result = expr.getEnclosingCallable().getReturnType() }
override ControlFlow::Node getControlFlowNodeImpl() { result = cfn }
override Location getLocationImpl() { result = rs.getLocation() }
override Location getLocationImpl() { result = expr.getLocation() }
override string toStringImpl() { result = rs.toString() }
override string toStringImpl() { result = expr.toString() }
}
/**

View File

@@ -29,7 +29,7 @@ class Test
public void TestAwait3(string input)
{
Sink(ReturnAwait(input).Result);
Sink(ReturnAwait2(input).Result);
}
private async Task<string> ReturnAwait(string x)
@@ -47,4 +47,6 @@ class Test
{
return Task.FromResult(x);
}
private async Task<string> ReturnAwait2(string x) => x;
}

View File

@@ -10,19 +10,20 @@ edges
| Async.cs:26:17:26:40 | await ... : String | Async.cs:27:14:27:14 | access to local variable x |
| Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String | Async.cs:26:17:26:40 | await ... : String |
| Async.cs:26:35:26:39 | access to parameter input : String | Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String |
| Async.cs:30:35:30:39 | input : String | Async.cs:32:26:32:30 | access to parameter input : String |
| Async.cs:32:14:32:31 | call to method ReturnAwait [Result] : String | Async.cs:32:14:32:38 | access to property Result |
| Async.cs:32:26:32:30 | access to parameter input : String | Async.cs:32:14:32:31 | call to method ReturnAwait [Result] : String |
| Async.cs:30:35:30:39 | input : String | Async.cs:32:27:32:31 | access to parameter input : String |
| Async.cs:32:14:32:32 | call to method ReturnAwait2 [Result] : String | Async.cs:32:14:32:39 | access to property Result |
| Async.cs:32:27:32:31 | access to parameter input : String | Async.cs:32:14:32:32 | call to method ReturnAwait2 [Result] : String |
| Async.cs:35:51:35:51 | x : String | Async.cs:38:16:38:16 | access to parameter x : String |
| Async.cs:38:16:38:16 | access to parameter x : String | Async.cs:21:20:21:37 | call to method ReturnAwait [Result] : String |
| Async.cs:38:16:38:16 | access to parameter x : String | Async.cs:26:23:26:40 | call to method ReturnAwait [Result] : String |
| Async.cs:38:16:38:16 | access to parameter x : String | Async.cs:32:14:32:31 | call to method ReturnAwait [Result] : String |
| Async.cs:41:33:41:37 | input : String | Async.cs:43:25:43:29 | access to parameter input : String |
| Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String | Async.cs:43:14:43:37 | access to property Result |
| Async.cs:43:25:43:29 | access to parameter input : String | Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String |
| Async.cs:46:44:46:44 | x : String | Async.cs:48:32:48:32 | access to parameter x : String |
| Async.cs:48:16:48:33 | call to method FromResult [Result] : String | Async.cs:43:14:43:30 | call to method ReturnTask [Result] : String |
| Async.cs:48:32:48:32 | access to parameter x : String | Async.cs:48:16:48:33 | call to method FromResult [Result] : String |
| Async.cs:51:52:51:52 | x : String | Async.cs:51:58:51:58 | access to parameter x : String |
| Async.cs:51:58:51:58 | access to parameter x : String | Async.cs:32:14:32:32 | call to method ReturnAwait2 [Result] : String |
nodes
| Async.cs:9:37:9:41 | input : String | semmle.label | input : String |
| Async.cs:11:14:11:26 | call to method Return | semmle.label | call to method Return |
@@ -39,9 +40,9 @@ nodes
| Async.cs:26:35:26:39 | access to parameter input : String | semmle.label | access to parameter input : String |
| Async.cs:27:14:27:14 | access to local variable x | semmle.label | access to local variable x |
| Async.cs:30:35:30:39 | input : String | semmle.label | input : String |
| Async.cs:32:14:32:31 | call to method ReturnAwait [Result] : String | semmle.label | call to method ReturnAwait [Result] : String |
| Async.cs:32:14:32:38 | access to property Result | semmle.label | access to property Result |
| Async.cs:32:26:32:30 | access to parameter input : String | semmle.label | access to parameter input : String |
| Async.cs:32:14:32:32 | call to method ReturnAwait2 [Result] : String | semmle.label | call to method ReturnAwait2 [Result] : String |
| Async.cs:32:14:32:39 | access to property Result | semmle.label | access to property Result |
| Async.cs:32:27:32:31 | access to parameter input : String | semmle.label | access to parameter input : String |
| Async.cs:35:51:35:51 | x : String | semmle.label | x : String |
| Async.cs:38:16:38:16 | access to parameter x : String | semmle.label | access to parameter x : String |
| Async.cs:41:33:41:37 | input : String | semmle.label | input : String |
@@ -51,6 +52,8 @@ nodes
| Async.cs:46:44:46:44 | x : String | semmle.label | x : String |
| Async.cs:48:16:48:33 | call to method FromResult [Result] : String | semmle.label | call to method FromResult [Result] : String |
| Async.cs:48:32:48:32 | access to parameter x : String | semmle.label | access to parameter x : String |
| Async.cs:51:52:51:52 | x : String | semmle.label | x : String |
| Async.cs:51:58:51:58 | access to parameter x : String | semmle.label | access to parameter x : String |
#select
| 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 |
| 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 |
@@ -58,7 +61,7 @@ nodes
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |