Skip to content

Commit c39bca5

Browse files
committed
C#: Model data-flow for System.Threading.Tasks.Task<T>.GetAwaiter()
1 parent c0b251a commit c39bca5

File tree

5 files changed

+74
-4
lines changed

5 files changed

+74
-4
lines changed

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

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ private import semmle.code.csharp.frameworks.system.io.Compression
1111
private import semmle.code.csharp.frameworks.system.linq.Expressions
1212
private import semmle.code.csharp.frameworks.system.Net
1313
private import semmle.code.csharp.frameworks.system.Text
14+
private import semmle.code.csharp.frameworks.system.runtime.CompilerServices
1415
private import semmle.code.csharp.frameworks.system.threading.Tasks
1516
private import semmle.code.csharp.frameworks.system.Web
1617
private import semmle.code.csharp.frameworks.system.web.ui.WebControls
@@ -95,6 +96,11 @@ module AccessPath {
9596
result = singleton(any(PropertyContent c | c.getProperty() = p.getSourceDeclaration()))
9697
}
9798

99+
/** Gets a singleton field access path. */
100+
AccessPath field(Field f) {
101+
result = singleton(any(FieldContent c | c.getField() = f.getSourceDeclaration()))
102+
}
103+
98104
/** Gets an access path representing a property inside a collection. */
99105
AccessPath properties(Property p) { result = TConsAccessPath(any(ElementContent c), property(p)) }
100106
}
@@ -1714,9 +1720,7 @@ class SystemThreadingTasksTaskFlow extends LibraryTypeDataFlow, SystemThreadingT
17141720
}
17151721

17161722
/** Data flow for `System.Threading.Tasks.Task<>`. */
1717-
class SystemThreadingTasksTaskTFlow extends LibraryTypeDataFlow {
1718-
SystemThreadingTasksTaskTFlow() { this instanceof SystemThreadingTasksTaskTClass }
1719-
1723+
class SystemThreadingTasksTaskTFlow extends LibraryTypeDataFlow, SystemThreadingTasksTaskTClass {
17201724
override predicate callableFlow(
17211725
CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp,
17221726
SourceDeclarationCallable c, boolean preservesValue
@@ -1807,6 +1811,14 @@ class SystemThreadingTasksTaskTFlow extends LibraryTypeDataFlow {
18071811
sinkAp = AccessPath::property(this.(SystemThreadingTasksTaskTClass).getResultProperty())
18081812
)
18091813
)
1814+
or
1815+
m = this.getGetAwaiterMethod() and
1816+
source = TCallableFlowSourceQualifier() and
1817+
sourceAp = AccessPath::empty() and
1818+
sink = TCallableFlowSinkReturn() and
1819+
sinkAp =
1820+
AccessPath::field(any(SystemRuntimeCompilerServicesTaskAwaiterStruct s)
1821+
.getUnderlyingTaskField())
18101822
}
18111823
}
18121824

@@ -1891,6 +1903,29 @@ class SystemThreadingTasksFactoryFlow extends LibraryTypeDataFlow {
18911903
}
18921904
}
18931905

1906+
/** Data flow for `System.Runtime.CompilerServices.TaskAwaiter<>`. */
1907+
class SystemRuntimeCompilerServicesTaskAwaiterFlow extends LibraryTypeDataFlow,
1908+
SystemRuntimeCompilerServicesTaskAwaiterStruct {
1909+
override predicate callableFlow(
1910+
CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp,
1911+
SourceDeclarationCallable c, boolean preservesValue
1912+
) {
1913+
preservesValue = true and
1914+
c = this.getGetResultMethod() and
1915+
source = TCallableFlowSourceQualifier() and
1916+
sourceAp =
1917+
AccessPath::cons(any(FieldContent fc | fc.getField() = this.getUnderlyingTaskField()),
1918+
AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())) and
1919+
sink = TCallableFlowSinkReturn() and
1920+
sinkAp = AccessPath::empty()
1921+
}
1922+
1923+
override predicate requiresAccessPath(Content head, AccessPath tail) {
1924+
head.(FieldContent).getField() = this.getUnderlyingTaskField() and
1925+
tail = AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())
1926+
}
1927+
}
1928+
18941929
/** Data flow for `System.Text.Encoding`. */
18951930
library class SystemTextEncodingFlow extends LibraryTypeDataFlow, SystemTextEncodingClass {
18961931
override predicate callableFlow(
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/** Provides definitions related to the namespace `System.Runtime.CompilerServices`. */
2+
3+
import csharp
4+
private import semmle.code.csharp.frameworks.system.Runtime
5+
6+
/** The `System.Runtime.CompilerServices` namespace. */
7+
class SystemRuntimeCompilerServicesNamespace extends Namespace {
8+
SystemRuntimeCompilerServicesNamespace() {
9+
this.getParentNamespace() instanceof SystemRuntimeNamespace and
10+
this.hasName("CompilerServices")
11+
}
12+
}
13+
14+
/** An unbound generic struct in the `System.Runtime.CompilerServices` namespace. */
15+
class SystemRuntimeCompilerServicesNamespaceUnboundGenericStruct extends UnboundGenericStruct {
16+
SystemRuntimeCompilerServicesNamespaceUnboundGenericStruct() {
17+
this = any(SystemRuntimeCompilerServicesNamespace n).getATypeDeclaration()
18+
}
19+
}
20+
21+
/** The `System.Runtime.CompilerServices.TaskAwaiter<>` struct. */
22+
class SystemRuntimeCompilerServicesTaskAwaiterStruct extends SystemRuntimeCompilerServicesNamespaceUnboundGenericStruct {
23+
SystemRuntimeCompilerServicesTaskAwaiterStruct() { this.hasName("TaskAwaiter<>") }
24+
25+
/** Gets the `GetResult` method. */
26+
Method getGetResultMethod() { result = this.getAMethod("GetResult") }
27+
28+
/** Gets the field that stores the underlying task. */
29+
Field getUnderlyingTaskField() { result = this.getAField() and result.hasName("m_task") }
30+
}

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
@@ -38,4 +38,7 @@ class SystemThreadingTasksTaskTClass extends SystemThreadingTasksUnboundGenericC
3838
result.hasName("Result") and
3939
result.getType() = this.getTypeParameter(0)
4040
}
41+
42+
/** Gets the `GetAwaiter` method. */
43+
Method getGetAwaiterMethod() { result = this.getAMethod("GetAwaiter") }
4144
}

csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ void M()
8585
HttpContextBase context = null;
8686
string name = context.Request.QueryString["name"];
8787

88-
var dict = new Dictionary<string, int>() { {"abc", 0 } };
88+
var dict = new Dictionary<string, int>() { { "abc", 0 } };
8989
}
9090

9191
[DataContract]

csharp/ql/test/library-tests/dataflow/library/LibraryTypeDataFlow.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1780,6 +1780,7 @@ callableFlowAccessPath
17801780
| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.Reverse(int, int) | argument 0 [[]] -> return [[]] | true |
17811781
| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.get_Item(int) | qualifier [[]] -> return [<empty>] | true |
17821782
| System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.set_Item(int, T) | argument 1 [<empty>] -> qualifier [[]] | true |
1783+
| System.Runtime.CompilerServices.TaskAwaiter<>.GetResult() | qualifier [m_task, Result] -> return [<empty>] | true |
17831784
| System.Security.PermissionSet.CopyTo(Array, int) | qualifier [[]] -> argument 0 [[]] | true |
17841785
| System.Security.PermissionSet.GetEnumerator() | qualifier [[]] -> return [Current] | true |
17851786
| System.String.Concat(IEnumerable<String>) | argument 0 [[]] -> return [<empty>] | false |
@@ -1929,6 +1930,7 @@ callableFlowAccessPath
19291930
| System.Threading.Tasks.Task<>.ContinueWith<TNewResult>(Func<Task<>, TNewResult>, CancellationToken, TaskContinuationOptions, TaskScheduler) | output from argument 0 [<empty>] -> return [Result] | true |
19301931
| System.Threading.Tasks.Task<>.ContinueWith<TNewResult>(Func<Task<>, TNewResult>, TaskContinuationOptions) | output from argument 0 [<empty>] -> return [Result] | true |
19311932
| System.Threading.Tasks.Task<>.ContinueWith<TNewResult>(Func<Task<>, TNewResult>, TaskScheduler) | output from argument 0 [<empty>] -> return [Result] | true |
1933+
| System.Threading.Tasks.Task<>.GetAwaiter() | qualifier [<empty>] -> return [m_task] | true |
19321934
| System.Threading.Tasks.Task<>.Task(Func<Object, TResult>, object) | output from argument 0 [<empty>] -> return [Result] | true |
19331935
| System.Threading.Tasks.Task<>.Task(Func<Object, TResult>, object, CancellationToken) | output from argument 0 [<empty>] -> return [Result] | true |
19341936
| System.Threading.Tasks.Task<>.Task(Func<Object, TResult>, object, CancellationToken, TaskCreationOptions) | output from argument 0 [<empty>] -> return [Result] | true |

0 commit comments

Comments
 (0)