Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 342a711

Browse files
committed
C#: Add flow summary for 'Task.ConfigureAwait()'
1 parent a1b59e2 commit 342a711

4 files changed

Lines changed: 114 additions & 0 deletions

File tree

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

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,6 +1843,53 @@ class SystemThreadingTasksTaskTFlow extends LibraryTypeDataFlow, SystemThreading
18431843
sinkAp =
18441844
AccessPath::field(any(SystemRuntimeCompilerServicesTaskAwaiterStruct s)
18451845
.getUnderlyingTaskField())
1846+
or
1847+
// var awaitable = task.ConfigureAwait(false); // <-- new ConfiguredTaskAwaitable<>(task, false)
1848+
// // m_configuredTaskAwaiter = new ConfiguredTaskAwaiter(task, false)
1849+
// // m_task = task
1850+
// var awaiter = awaitable.GetAwaiter();
1851+
// var result = awaiter.GetResult();
1852+
m = this.getConfigureAwaitMethod() and
1853+
source = TCallableFlowSourceQualifier() and
1854+
sourceAp = AccessPath::empty() and
1855+
sink = TCallableFlowSinkReturn() and
1856+
sinkAp =
1857+
AccessPath::cons(any(FieldContent fc |
1858+
fc.getField() =
1859+
any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct t)
1860+
.getUnderlyingAwaiterField()
1861+
),
1862+
AccessPath::field(any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct s
1863+
).getUnderlyingTaskField()))
1864+
}
1865+
1866+
override predicate requiresAccessPath(Content head, AccessPath tail) {
1867+
head.(FieldContent).getField() =
1868+
any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct t).getUnderlyingAwaiterField() and
1869+
tail =
1870+
AccessPath::field(any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct s
1871+
).getUnderlyingTaskField())
1872+
}
1873+
}
1874+
1875+
/** Data flow for `System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>`. */
1876+
private class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTFlow extends LibraryTypeDataFlow,
1877+
SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct {
1878+
override predicate callableFlow(
1879+
CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp,
1880+
SourceDeclarationCallable c, boolean preservesValue
1881+
) {
1882+
// var awaitable = task.ConfigureAwait(false);
1883+
// var awaiter = awaitable.GetAwaiter(); // <-- awaitable.m_configuredTaskAwaiter
1884+
// var result = awaiter.GetResult();
1885+
c = this.getGetAwaiterMethod() and
1886+
source = TCallableFlowSourceQualifier() and
1887+
sourceAp =
1888+
AccessPath::field(any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct s)
1889+
.getUnderlyingAwaiterField()) and
1890+
sink = TCallableFlowSinkReturn() and
1891+
sinkAp = AccessPath::empty() and
1892+
preservesValue = true
18461893
}
18471894
}
18481895

@@ -1950,6 +1997,32 @@ class SystemRuntimeCompilerServicesTaskAwaiterFlow extends LibraryTypeDataFlow,
19501997
}
19511998
}
19521999

2000+
/** Data flow for `System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>.ConfiguredTaskAwaiter`. */
2001+
class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterFlow extends LibraryTypeDataFlow,
2002+
SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct {
2003+
override predicate callableFlow(
2004+
CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp,
2005+
SourceDeclarationCallable c, boolean preservesValue
2006+
) {
2007+
// var awaitable = task.ConfigureAwait(false);
2008+
// var awaiter = awaitable.GetAwaiter();
2009+
// var result = awaiter.GetResult(); // <-- task.Result
2010+
preservesValue = true and
2011+
c = this.getGetResultMethod() and
2012+
source = TCallableFlowSourceQualifier() and
2013+
sourceAp =
2014+
AccessPath::cons(any(FieldContent fc | fc.getField() = this.getUnderlyingTaskField()),
2015+
AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())) and
2016+
sink = TCallableFlowSinkReturn() and
2017+
sinkAp = AccessPath::empty()
2018+
}
2019+
2020+
override predicate requiresAccessPath(Content head, AccessPath tail) {
2021+
head.(FieldContent).getField() = this.getUnderlyingTaskField() and
2022+
tail = AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())
2023+
}
2024+
}
2025+
19532026
/** Data flow for `System.Text.Encoding`. */
19542027
library class SystemTextEncodingFlow extends LibraryTypeDataFlow, SystemTextEncodingClass {
19552028
override predicate callableFlow(

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,38 @@ 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+
/** An unbound generic struct in the `System.Runtime.CompilerServices` namespace. */
48+
class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStructStruct extends Struct {
49+
SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStructStruct() {
50+
this = any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct n).getANestedType()
51+
}
52+
}
53+
54+
/** The `System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>.ConfiguredTaskAwaiter` struct. */
55+
class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct extends SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStructStruct {
56+
SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct() {
57+
this.hasName("ConfiguredTaskAwaiter")
58+
}
59+
60+
/** Gets the `GetResult` method. */
61+
Method getGetResultMethod() { result = this.getAMethod("GetResult") }
62+
63+
/** Gets the field that stores the underlying task. */
64+
Field getUnderlyingTaskField() { result = this.getAField() and result.hasName("m_task") }
65+
}

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/library/LibraryTypeDataFlow.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,6 +1776,8 @@ callableFlowAccessPath
17761776
| System.Resources.ResourceReader.GetEnumerator() | qualifier [[]] -> return [Current] | true |
17771777
| System.Resources.ResourceSet.GetEnumerator() | qualifier [[]] -> return [Current] | true |
17781778
| System.Runtime.CompilerServices.ConditionalWeakTable<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true |
1779+
| System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>.ConfiguredTaskAwaiter.GetResult() | qualifier [m_task, Result] -> return [<empty>] | true |
1780+
| System.Runtime.CompilerServices.ConfiguredTaskAwaitable<>.GetAwaiter() | qualifier [m_configuredTaskAwaiter] -> return [<empty>] | true |
17791781
| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(T) | argument 0 [<empty>] -> qualifier [[]] | true |
17801782
| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Add(object) | argument 0 [<empty>] -> qualifier [[]] | true |
17811783
| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true |
@@ -1927,6 +1929,7 @@ callableFlowAccessPath
19271929
| System.Threading.Tasks.Task.WhenAll<TResult>(params Task<TResult>[]) | argument 0 [[], Result] -> return [Result, []] | true |
19281930
| System.Threading.Tasks.Task.WhenAny<TResult>(IEnumerable<Task<TResult>>) | argument 0 [[], Result] -> return [Result, []] | true |
19291931
| System.Threading.Tasks.Task.WhenAny<TResult>(params Task<TResult>[]) | argument 0 [[], Result] -> return [Result, []] | true |
1932+
| System.Threading.Tasks.Task<>.ConfigureAwait(bool) | qualifier [<empty>] -> return [m_configuredTaskAwaiter, m_task] | true |
19301933
| System.Threading.Tasks.Task<>.ContinueWith<TNewResult>(Func<Task<>, Object, TNewResult>, object) | output from argument 0 [<empty>] -> return [Result] | true |
19311934
| System.Threading.Tasks.Task<>.ContinueWith<TNewResult>(Func<Task<>, Object, TNewResult>, object, CancellationToken) | output from argument 0 [<empty>] -> return [Result] | true |
19321935
| System.Threading.Tasks.Task<>.ContinueWith<TNewResult>(Func<Task<>, Object, TNewResult>, object, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 [<empty>] -> return [Result] | true |

0 commit comments

Comments
 (0)