Skip to content

Commit 69ba2e6

Browse files
authored
Merge pull request #7337 from michaelnebel/csharp-synthetic-field
C#: Introduce synthetic fields and use them in Task<>.
2 parents b49ca6a + 13347cd commit 69ba2e6

File tree

8 files changed

+107
-43
lines changed

8 files changed

+107
-43
lines changed

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

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ module AccessPath {
102102
result = singleton(any(FieldContent c | c.getField() = f.getUnboundDeclaration()))
103103
}
104104

105+
/** Gets a singleton synthetic field access path. */
106+
AccessPath synthetic(SyntheticField f) {
107+
result = singleton(any(SyntheticFieldContent c | c.getField() = f))
108+
}
109+
105110
/** Gets an access path representing a property inside a collection. */
106111
AccessPath properties(Property p) { result = TConsAccessPath(any(ElementContent c), property(p)) }
107112
}
@@ -1968,9 +1973,7 @@ class SystemThreadingTasksTaskTFlow extends LibraryTypeDataFlow, SystemThreading
19681973
source = TCallableFlowSourceQualifier() and
19691974
sourceAp = AccessPath::empty() and
19701975
sink = TCallableFlowSinkReturn() and
1971-
sinkAp =
1972-
AccessPath::field(any(SystemRuntimeCompilerServicesTaskAwaiterStruct s)
1973-
.getUnderlyingTaskField())
1976+
sinkAp = AccessPath::synthetic(any(SyntheticTaskAwaiterUnderlyingTaskField s))
19741977
or
19751978
// var awaitable = task.ConfigureAwait(false); // <-- new ConfiguredTaskAwaitable<>(task, false)
19761979
// // m_configuredTaskAwaiter = new ConfiguredTaskAwaiter(task, false)
@@ -1982,21 +1985,40 @@ class SystemThreadingTasksTaskTFlow extends LibraryTypeDataFlow, SystemThreading
19821985
sourceAp = AccessPath::empty() and
19831986
sink = TCallableFlowSinkReturn() and
19841987
sinkAp =
1985-
AccessPath::cons(any(FieldContent fc |
1986-
fc.getField() =
1987-
any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct t)
1988-
.getUnderlyingAwaiterField()
1989-
),
1990-
AccessPath::field(any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct s
1991-
).getUnderlyingTaskField()))
1988+
AccessPath::cons(any(SyntheticFieldContent sfc |
1989+
sfc.getField() instanceof SyntheticConfiguredTaskAwaiterField
1990+
), AccessPath::synthetic(any(SyntheticConfiguredTaskAwaitableUnderlyingTaskField s)))
19921991
}
19931992

19941993
override predicate requiresAccessPath(Content head, AccessPath tail) {
1995-
head.(FieldContent).getField() =
1996-
any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct t).getUnderlyingAwaiterField() and
1997-
tail =
1998-
AccessPath::field(any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct s
1999-
).getUnderlyingTaskField())
1994+
head.(SyntheticFieldContent).getField() instanceof SyntheticConfiguredTaskAwaiterField and
1995+
tail = AccessPath::synthetic(any(SyntheticConfiguredTaskAwaitableUnderlyingTaskField s))
1996+
}
1997+
}
1998+
1999+
abstract private class SyntheticTaskField extends SyntheticField {
2000+
bindingset[this]
2001+
SyntheticTaskField() { any() }
2002+
2003+
override Type getType() { result instanceof SystemThreadingTasksTaskTClass }
2004+
}
2005+
2006+
private class SyntheticTaskAwaiterUnderlyingTaskField extends SyntheticTaskField {
2007+
SyntheticTaskAwaiterUnderlyingTaskField() { this = "m_task_task_awaiter" }
2008+
}
2009+
2010+
private class SyntheticConfiguredTaskAwaitableUnderlyingTaskField extends SyntheticTaskField {
2011+
SyntheticConfiguredTaskAwaitableUnderlyingTaskField() {
2012+
this = "m_task_configured_task_awaitable"
2013+
}
2014+
}
2015+
2016+
private class SyntheticConfiguredTaskAwaiterField extends SyntheticField {
2017+
SyntheticConfiguredTaskAwaiterField() { this = "m_configuredTaskAwaiter" }
2018+
2019+
override Type getType() {
2020+
result instanceof
2021+
SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiterStruct
20002022
}
20012023
}
20022024

@@ -2012,9 +2034,7 @@ private class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTFlow extends
20122034
// var result = awaiter.GetResult();
20132035
c = this.getGetAwaiterMethod() and
20142036
source = TCallableFlowSourceQualifier() and
2015-
sourceAp =
2016-
AccessPath::field(any(SystemRuntimeCompilerServicesConfiguredTaskAwaitableTStruct s)
2017-
.getUnderlyingAwaiterField()) and
2037+
sourceAp = AccessPath::synthetic(any(SyntheticConfiguredTaskAwaiterField s)) and
20182038
sink = TCallableFlowSinkReturn() and
20192039
sinkAp = AccessPath::empty() and
20202040
preservesValue = true
@@ -2113,14 +2133,15 @@ class SystemRuntimeCompilerServicesTaskAwaiterFlow extends LibraryTypeDataFlow,
21132133
c = this.getGetResultMethod() and
21142134
source = TCallableFlowSourceQualifier() and
21152135
sourceAp =
2116-
AccessPath::cons(any(FieldContent fc | fc.getField() = this.getUnderlyingTaskField()),
2117-
AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())) and
2136+
AccessPath::cons(any(SyntheticFieldContent sfc |
2137+
sfc.getField() instanceof SyntheticTaskAwaiterUnderlyingTaskField
2138+
), AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())) and
21182139
sink = TCallableFlowSinkReturn() and
21192140
sinkAp = AccessPath::empty()
21202141
}
21212142

21222143
override predicate requiresAccessPath(Content head, AccessPath tail) {
2123-
head.(FieldContent).getField() = this.getUnderlyingTaskField() and
2144+
head.(SyntheticFieldContent).getField() instanceof SyntheticTaskAwaiterUnderlyingTaskField and
21242145
tail = AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())
21252146
}
21262147
}
@@ -2139,14 +2160,16 @@ class SystemRuntimeCompilerServicesConfiguredTaskAwaitableTConfiguredTaskAwaiter
21392160
c = this.getGetResultMethod() and
21402161
source = TCallableFlowSourceQualifier() and
21412162
sourceAp =
2142-
AccessPath::cons(any(FieldContent fc | fc.getField() = this.getUnderlyingTaskField()),
2143-
AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())) and
2163+
AccessPath::cons(any(SyntheticFieldContent sfc |
2164+
sfc.getField() instanceof SyntheticConfiguredTaskAwaitableUnderlyingTaskField
2165+
), AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())) and
21442166
sink = TCallableFlowSinkReturn() and
21452167
sinkAp = AccessPath::empty()
21462168
}
21472169

21482170
override predicate requiresAccessPath(Content head, AccessPath tail) {
2149-
head.(FieldContent).getField() = this.getUnderlyingTaskField() and
2171+
head.(SyntheticFieldContent).getField() instanceof
2172+
SyntheticConfiguredTaskAwaitableUnderlyingTaskField and
21502173
tail = AccessPath::property(any(SystemThreadingTasksTaskTClass t).getResultProperty())
21512174
}
21522175
}

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,8 @@ private module Cached {
759759
newtype TContent =
760760
TFieldContent(Field f) { f.isUnboundDeclaration() } or
761761
TPropertyContent(Property p) { p.isUnboundDeclaration() } or
762-
TElementContent()
762+
TElementContent() or
763+
TSyntheticFieldContent(SyntheticField f)
763764

764765
pragma[nomagic]
765766
private predicate commonSubTypeGeneral(DataFlowTypeOrUnifiable t1, RelevantDataFlowType t2) {
@@ -2038,3 +2039,12 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
20382039
predicate allowParameterReturnInSelf(ParameterNode p) {
20392040
FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(p)
20402041
}
2042+
2043+
/** A synthetic field. */
2044+
abstract class SyntheticField extends string {
2045+
bindingset[this]
2046+
SyntheticField() { any() }
2047+
2048+
/** Gets the type of this synthetic field. */
2049+
Type getType() { result instanceof ObjectType }
2050+
}

csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,18 @@ class FieldContent extends Content, TFieldContent {
224224
deprecated override Gvn::GvnType getType() { result = Gvn::getGlobalValueNumber(f.getType()) }
225225
}
226226

227+
/** A reference to a synthetic field. */
228+
class SyntheticFieldContent extends Content, TSyntheticFieldContent {
229+
private SyntheticField f;
230+
231+
SyntheticFieldContent() { this = TSyntheticFieldContent(f) }
232+
233+
/** Gets the underlying synthetic field. */
234+
SyntheticField getField() { result = f }
235+
236+
override string toString() { result = "synthetic " + f.toString() }
237+
}
238+
227239
/** A reference to a property. */
228240
class PropertyContent extends Content, TPropertyContent {
229241
private Property p;

csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ DataFlowType getContentType(Content c) {
2929
or
3030
t = c.(PropertyContent).getProperty().getType()
3131
or
32+
t = c.(SyntheticFieldContent).getField().getType()
33+
or
3234
c instanceof ElementContent and
3335
t instanceof ObjectType // we don't know what the actual element type is
3436
)
@@ -134,6 +136,11 @@ SummaryComponent interpretComponentSpecific(string c) {
134136
c.regexpCapture("Property\\[(.+)\\]", 1) = p.getQualifiedName() and
135137
result = SummaryComponent::content(any(PropertyContent pc | pc.getProperty() = p))
136138
)
139+
or
140+
exists(SyntheticField f |
141+
c.regexpCapture("SyntheticField\\[(.+)\\]", 1) = f and
142+
result = SummaryComponent::content(any(SyntheticFieldContent sfc | sfc.getField() = f))
143+
)
137144
}
138145

139146
/** Gets the textual representation of the content in the format used for flow summaries. */
@@ -143,6 +150,8 @@ private string getContentSpecificCsv(Content c) {
143150
exists(Field f | c = TFieldContent(f) and result = "Field[" + f.getQualifiedName() + "]")
144151
or
145152
exists(Property p | c = TPropertyContent(p) and result = "Property[" + p.getQualifiedName() + "]")
153+
or
154+
exists(SyntheticField f | c = TSyntheticFieldContent(f) and result = "SyntheticField[" + f + "]")
146155
}
147156

148157
/** Gets the textual representation of a summary component in the format used for flow summaries. */

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -253,11 +253,11 @@ edges
253253
| GlobalDataFlow.cs:438:22:438:35 | "taint source" : String | GlobalDataFlow.cs:201:22:201:32 | access to property OutProperty : String |
254254
| GlobalDataFlow.cs:474:20:474:49 | call to method Run<String> [property Result] : String | GlobalDataFlow.cs:475:25:475:28 | access to local variable task [property Result] : String |
255255
| GlobalDataFlow.cs:474:35:474:48 | "taint source" : String | GlobalDataFlow.cs:474:20:474:49 | call to method Run<String> [property Result] : String |
256-
| GlobalDataFlow.cs:475:25:475:28 | access to local variable task [property Result] : String | GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String |
257-
| GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String |
258-
| GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [field m_task, property Result] : String |
259-
| GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [field m_task, property Result] : String | GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [field m_task, property Result] : String |
260-
| GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [field m_task, property Result] : String | GlobalDataFlow.cs:477:22:477:40 | call to method GetResult : String |
256+
| GlobalDataFlow.cs:475:25:475:28 | access to local variable task [property Result] : String | GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String |
257+
| GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String |
258+
| GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [synthetic m_task_configured_task_awaitable, property Result] : String |
259+
| GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [synthetic m_task_configured_task_awaitable, property Result] : String | GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [synthetic m_task_configured_task_awaitable, property Result] : String |
260+
| GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [synthetic m_task_configured_task_awaitable, property Result] : String | GlobalDataFlow.cs:477:22:477:40 | call to method GetResult : String |
261261
| GlobalDataFlow.cs:477:22:477:40 | call to method GetResult : String | GlobalDataFlow.cs:478:15:478:20 | access to local variable sink45 |
262262
| GlobalDataFlow.cs:483:53:483:55 | arg : String | GlobalDataFlow.cs:487:15:487:17 | access to parameter arg : String |
263263
| GlobalDataFlow.cs:486:21:486:21 | s : String | GlobalDataFlow.cs:486:32:486:32 | access to parameter s |
@@ -513,10 +513,10 @@ nodes
513513
| GlobalDataFlow.cs:474:20:474:49 | call to method Run<String> [property Result] : String | semmle.label | call to method Run<String> [property Result] : String |
514514
| GlobalDataFlow.cs:474:35:474:48 | "taint source" : String | semmle.label | "taint source" : String |
515515
| GlobalDataFlow.cs:475:25:475:28 | access to local variable task [property Result] : String | semmle.label | access to local variable task [property Result] : String |
516-
| GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String | semmle.label | call to method ConfigureAwait [field m_configuredTaskAwaiter, field m_task, property Result] : String |
517-
| GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String | semmle.label | access to local variable awaitable [field m_configuredTaskAwaiter, field m_task, property Result] : String |
518-
| GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [field m_task, property Result] : String | semmle.label | call to method GetAwaiter [field m_task, property Result] : String |
519-
| GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [field m_task, property Result] : String | semmle.label | access to local variable awaiter [field m_task, property Result] : String |
516+
| GlobalDataFlow.cs:475:25:475:50 | call to method ConfigureAwait [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | semmle.label | call to method ConfigureAwait [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String |
517+
| GlobalDataFlow.cs:476:23:476:31 | access to local variable awaitable [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String | semmle.label | access to local variable awaitable [synthetic m_configuredTaskAwaiter, synthetic m_task_configured_task_awaitable, property Result] : String |
518+
| GlobalDataFlow.cs:476:23:476:44 | call to method GetAwaiter [synthetic m_task_configured_task_awaitable, property Result] : String | semmle.label | call to method GetAwaiter [synthetic m_task_configured_task_awaitable, property Result] : String |
519+
| GlobalDataFlow.cs:477:22:477:28 | access to local variable awaiter [synthetic m_task_configured_task_awaitable, property Result] : String | semmle.label | access to local variable awaiter [synthetic m_task_configured_task_awaitable, property Result] : String |
520520
| GlobalDataFlow.cs:477:22:477:40 | call to method GetResult : String | semmle.label | call to method GetResult : String |
521521
| GlobalDataFlow.cs:478:15:478:20 | access to local variable sink45 | semmle.label | access to local variable sink45 |
522522
| GlobalDataFlow.cs:483:53:483:55 | arg : String | semmle.label | arg : String |

0 commit comments

Comments
 (0)