Skip to content

Commit 7c3964a

Browse files
authored
Merge pull request #4543 from tamasvajk/feature/configureawait
C#: Add flow summary for 'Task.ConfigureAwait()'
2 parents 02ca8fe + 7a1e199 commit 7c3964a

File tree

10 files changed

+161
-1
lines changed

10 files changed

+161
-1
lines changed

csharp/ql/src/semmle/code/csharp/dataflow/LibraryTypeDataFlow.qll

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,6 +1904,53 @@ class SystemThreadingTasksTaskTFlow extends LibraryTypeDataFlow, SystemThreading
19041904
sinkAp =
19051905
AccessPath::field(any(SystemRuntimeCompilerServicesTaskAwaiterStruct s)
19061906
.getUnderlyingTaskField())
1907+
or
1908+
// var awaitable = task.ConfigureAwait(false); // <-- new ConfiguredTaskAwaitable<>(task, false)
1909+
// // m_configuredTaskAwaiter = new ConfiguredTaskAwaiter(task, false)
1910+
// // m_task = task
1911+
// var awaiter = awaitable.GetAwaiter();
1912+
// var result = awaiter.GetResult();
1913+
m = this.getConfigureAwaitMethod() and
1914+
source = TCallableFlowSourceQualifier() and
1915+
sourceAp = AccessPath::empty() and
1916+
sink = TCallableFlowSinkReturn() and
1917+
sinkAp =
1918+
AccessPath::cons(any(FieldContent fc |
1919+
fc.getField() =
1920+
any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct t)
1921+
.getUnderlyingAwaiterField()
1922+
),
1923+
AccessPath::field(any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct s
1924+
).getUnderlyingTaskField()))
1925+
}
1926+
1927+
override predicate requiresAccessPath(Content head, AccessPath tail) {
1928+
head.(FieldContent).getField() =
1929+
any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct t).getUnderlyingAwaiterField() and
1930+
tail =
1931+
AccessPath::field(any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct s
1932+
).getUnderlyingTaskField())
1933+
}
1934+
}
1935+
1936+
/** Data flow for `System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>`. */
1937+
private class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTFlow extends LibraryTypeDataFlow,
1938+
SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct {
1939+
override predicate callableFlow(
1940+
CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp,
1941+
SourceDeclarationCallable c, boolean preservesValue
1942+
) {
1943+
// var awaitable = task.ConfigureAwait(false);
1944+
// var awaiter = awaitable.GetAwaiter(); // <-- awaitable.m_configuredTaskAwaiter
1945+
// var result = awaiter.GetResult();
1946+
c = this.getGetAwaiterMethod() and
1947+
source = TCallableFlowSourceQualifier() and
1948+
sourceAp =
1949+
AccessPath::field(any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct s)
1950+
.getUnderlyingAwaiterField()) and
1951+
sink = TCallableFlowSinkReturn() and
1952+
sinkAp = AccessPath::empty() and
1953+
preservesValue = true
19071954
}
19081955
}
19091956

@@ -2011,6 +2058,32 @@ class SystemRuntimeCompilerServicesTaskAwaiterFlow extends LibraryTypeDataFlow,
20112058
}
20122059
}
20132060

2061+
/** Data flow for `System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>.ConfiguredTaskAwaiter`. */
2062+
class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterFlow extends LibraryTypeDataFlow,
2063+
SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct {
2064+
override predicate callableFlow(
2065+
CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp,
2066+
SourceDeclarationCallable c, boolean preservesValue
2067+
) {
2068+
// var awaitable = task.ConfigureAwait(false);
2069+
// var awaiter = awaitable.GetAwaiter();
2070+
// var result = awaiter.GetResult(); // <-- task.Result
2071+
preservesValue = true and
2072+
c = this.getGetResultMethod() and
2073+
source = TCallableFlowSourceQualifier() and
2074+
sourceAp =
2075+
AccessPath::cons(any(FieldContent fc | fc.getField() = this.getUnderlyingTaskField()),
2076+
AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())) and
2077+
sink = TCallableFlowSinkReturn() and
2078+
sinkAp = AccessPath::empty()
2079+
}
2080+
2081+
override predicate requiresAccessPath(Content head, AccessPath tail) {
2082+
head.(FieldContent).getField() = this.getUnderlyingTaskField() and
2083+
tail = AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())
2084+
}
2085+
}
2086+
20142087
/** Data flow for `System.Text.Encoding`. */
20152088
library class SystemTextEncodingFlow extends LibraryTypeDataFlow, SystemTextEncodingClass {
20162089
override predicate callableFlow(

csharp/ql/src/semmle/code/csharp/frameworks/system/runtime/CompilerServices.qll

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,32 @@ class SystemRuntimeCompilerServicesTaskAwaiterStruct extends SystemRuntimeCompil
2828
/** Gets the field that stores the underlying task. */
2929
Field getUnderlyingTaskField() { result = this.getAField() and result.hasName("m_task") }
3030
}
31+
32+
/** The `System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>` struct. */
33+
class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct extends SystemRuntimeCompilerServicesNamespaceUnboundGenericStruct {
34+
SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct() {
35+
this.hasName("ConfiguredTaskAwaitable<>")
36+
}
37+
38+
/** Gets the `GetAwaiter` method. */
39+
Method getGetAwaiterMethod() { result = this.getAMethod("GetAwaiter") }
40+
41+
/** Gets the field that stores the underlying awaiter. */
42+
Field getUnderlyingAwaiterField() {
43+
result = this.getAField() and result.hasName("m_configuredTaskAwaiter")
44+
}
45+
}
46+
47+
/** The `System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>.ConfiguredTaskAwaiter` struct. */
48+
class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct extends Struct {
49+
SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct() {
50+
this = any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct n).getANestedType() and
51+
this.hasName("ConfiguredTaskAwaiter")
52+
}
53+
54+
/** Gets the `GetResult` method. */
55+
Method getGetResultMethod() { result = this.getAMethod("GetResult") }
56+
57+
/** Gets the field that stores the underlying task. */
58+
Field getUnderlyingTaskField() { result = this.getAField() and result.hasName("m_task") }
59+
}

csharp/ql/src/semmle/code/csharp/frameworks/system/threading/Tasks.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,7 @@ class SystemThreadingTasksTaskTClass extends SystemThreadingTasksUnboundGenericC
4141

4242
/** Gets the `GetAwaiter` method. */
4343
Method getGetAwaiterMethod() { result = this.getAMethod("GetAwaiter") }
44+
45+
/** Gets the `ConfigureAwait` method. */
46+
Method getConfigureAwaitMethod() { result = this.getAMethod("ConfigureAwait") }
4447
}

csharp/ql/test/library-tests/dataflow/global/DataFlow.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
| GlobalDataFlow.cs:326:15:326:25 | access to parameter sinkParam11 |
5252
| GlobalDataFlow.cs:401:15:401:20 | access to local variable sink11 |
5353
| GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 |
54+
| GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 |
5455
| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x |
5556
| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x |
5657
| Splitting.cs:11:19:11:19 | access to local variable x |

csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,14 @@ edges
221221
| GlobalDataFlow.cs:402:16:402:21 | access to local variable sink11 : String | GlobalDataFlow.cs:164:22:164:43 | call to method TaintedParam : String |
222222
| GlobalDataFlow.cs:424:9:424:11 | value : String | GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 |
223223
| GlobalDataFlow.cs:435:22:435:35 | "taint source" : String | GlobalDataFlow.cs:198:22:198:32 | access to property OutProperty : String |
224+
| GlobalDataFlow.cs:471:20:471:49 | call to method Run [Result] : String | GlobalDataFlow.cs:472:25:472:28 | access to local variable task [Result] : String |
225+
| GlobalDataFlow.cs:471:35:471:48 | "taint source" : String | GlobalDataFlow.cs:471:20:471:49 | call to method Run [Result] : String |
226+
| GlobalDataFlow.cs:472:25:472:28 | access to local variable task [Result] : String | GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait [m_configuredTaskAwaiter, m_task, Result] : String |
227+
| GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait [m_configuredTaskAwaiter, m_task, Result] : String | GlobalDataFlow.cs:473:23:473:31 | access to local variable awaitable [m_configuredTaskAwaiter, m_task, Result] : String |
228+
| GlobalDataFlow.cs:473:23:473:31 | access to local variable awaitable [m_configuredTaskAwaiter, m_task, Result] : String | GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [m_task, Result] : String |
229+
| GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [m_task, Result] : String | GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String |
230+
| GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String |
231+
| GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 |
224232
| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted : String |
225233
| Splitting.cs:3:28:3:34 | tainted : String | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted : String |
226234
| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x |
@@ -428,6 +436,15 @@ nodes
428436
| GlobalDataFlow.cs:424:9:424:11 | value : String | semmle.label | value : String |
429437
| GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 | semmle.label | access to local variable sink20 |
430438
| GlobalDataFlow.cs:435:22:435:35 | "taint source" : String | semmle.label | "taint source" : String |
439+
| GlobalDataFlow.cs:471:20:471:49 | call to method Run [Result] : String | semmle.label | call to method Run [Result] : String |
440+
| GlobalDataFlow.cs:471:35:471:48 | "taint source" : String | semmle.label | "taint source" : String |
441+
| GlobalDataFlow.cs:472:25:472:28 | access to local variable task [Result] : String | semmle.label | access to local variable task [Result] : String |
442+
| GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait [m_configuredTaskAwaiter, m_task, Result] : String | semmle.label | call to method ConfigureAwait [m_configuredTaskAwaiter, m_task, Result] : String |
443+
| GlobalDataFlow.cs:473:23:473:31 | access to local variable awaitable [m_configuredTaskAwaiter, m_task, Result] : String | semmle.label | access to local variable awaitable [m_configuredTaskAwaiter, m_task, Result] : String |
444+
| GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter [m_task, Result] : String | semmle.label | call to method GetAwaiter [m_task, Result] : String |
445+
| GlobalDataFlow.cs:474:22:474:28 | access to local variable awaiter [m_task, Result] : String | semmle.label | access to local variable awaiter [m_task, Result] : String |
446+
| GlobalDataFlow.cs:474:22:474:40 | call to method GetResult : String | semmle.label | call to method GetResult : String |
447+
| GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | semmle.label | access to local variable sink45 |
431448
| Splitting.cs:3:28:3:34 | tainted : String | semmle.label | tainted : String |
432449
| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return : String | semmle.label | [b (line 3): false] call to method Return : String |
433450
| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return : String | semmle.label | [b (line 3): true] call to method Return : String |
@@ -498,6 +515,7 @@ nodes
498515
| Capture.cs:122:15:122:20 | access to local variable sink40 | Capture.cs:115:26:115:39 | "taint source" : String | Capture.cs:122:15:122:20 | access to local variable sink40 | access to local variable sink40 |
499516
| GlobalDataFlow.cs:240:15:240:20 | access to local variable sink41 | GlobalDataFlow.cs:238:35:238:48 | "taint source" : String | GlobalDataFlow.cs:240:15:240:20 | access to local variable sink41 | access to local variable sink41 |
500517
| GlobalDataFlow.cs:242:15:242:20 | access to local variable sink42 | GlobalDataFlow.cs:238:35:238:48 | "taint source" : String | GlobalDataFlow.cs:242:15:242:20 | access to local variable sink42 | access to local variable sink42 |
518+
| GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | GlobalDataFlow.cs:471:35:471:48 | "taint source" : String | GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 | access to local variable sink45 |
501519
| GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | GlobalDataFlow.cs:18:27:18:40 | "taint source" : String | GlobalDataFlow.cs:145:15:145:19 | access to local variable sink5 | access to local variable sink5 |
502520
| GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | GlobalDataFlow.cs:338:16:338:29 | "taint source" : String | GlobalDataFlow.cs:155:15:155:19 | access to local variable sink6 | access to local variable sink6 |
503521
| GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | GlobalDataFlow.cs:343:13:343:26 | "taint source" : String | GlobalDataFlow.cs:158:15:158:19 | access to local variable sink7 | access to local variable sink7 |

csharp/ql/test/library-tests/dataflow/global/GetAnOutNode.expected

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,12 @@
191191
| GlobalDataFlow.cs:456:23:456:35 | call to method ToString | return | GlobalDataFlow.cs:456:23:456:35 | call to method ToString |
192192
| GlobalDataFlow.cs:462:22:462:65 | call to method Join | return | GlobalDataFlow.cs:462:22:462:65 | call to method Join |
193193
| GlobalDataFlow.cs:465:23:465:65 | call to method Join | return | GlobalDataFlow.cs:465:23:465:65 | call to method Join |
194-
| GlobalDataFlow.cs:477:44:477:47 | delegate call | return | GlobalDataFlow.cs:477:44:477:47 | delegate call |
194+
| GlobalDataFlow.cs:471:20:471:49 | call to method Run | return | GlobalDataFlow.cs:471:20:471:49 | call to method Run |
195+
| GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait | qualifier | GlobalDataFlow.cs:472:25:472:28 | [post] access to local variable task |
196+
| GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait | return | GlobalDataFlow.cs:472:25:472:50 | call to method ConfigureAwait |
197+
| GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter | return | GlobalDataFlow.cs:473:23:473:44 | call to method GetAwaiter |
198+
| GlobalDataFlow.cs:474:22:474:40 | call to method GetResult | return | GlobalDataFlow.cs:474:22:474:40 | call to method GetResult |
199+
| GlobalDataFlow.cs:486:44:486:47 | delegate call | return | GlobalDataFlow.cs:486:44:486:47 | delegate call |
195200
| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | return | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return |
196201
| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | return | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return |
197202
| Splitting.cs:20:22:20:30 | call to method Return | return | Splitting.cs:20:22:20:30 | call to method Return |

csharp/ql/test/library-tests/dataflow/global/GlobalDataFlow.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,15 @@ void TestStringFlow()
465465
var nonSink = string.Join(",", "whatever", "not tainted");
466466
Check(nonSink);
467467
}
468+
469+
public void M4()
470+
{
471+
var task = Task.Run(() => "taint source");
472+
var awaitable = task.ConfigureAwait(false);
473+
var awaiter = awaitable.GetAwaiter();
474+
var sink45 = awaiter.GetResult();
475+
Check(sink45);
476+
}
468477
}
469478

470479
static class IEnumerableExtensions

csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
| GlobalDataFlow.cs:424:41:424:46 | access to local variable sink20 |
5858
| GlobalDataFlow.cs:453:15:453:20 | access to local variable sink43 |
5959
| GlobalDataFlow.cs:463:15:463:20 | access to local variable sink44 |
60+
| GlobalDataFlow.cs:475:15:475:20 | access to local variable sink45 |
6061
| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x |
6162
| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x |
6263
| Splitting.cs:11:19:11:19 | access to local variable x |

0 commit comments

Comments
 (0)