Skip to content

Commit ed6f873

Browse files
committed
Merge branch 'main' into rust-df-try-expr
2 parents 7092f13 + c0676f4 commit ed6f873

File tree

25 files changed

+462
-182
lines changed

25 files changed

+462
-182
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added support for data-flow through member accesses of objects with `dynamic` types.

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

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,17 @@ private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, b
883883
)
884884
)
885885
)
886+
or
887+
// A write to a dynamic property
888+
exists(DynamicMemberAccess dma, AssignableDefinition def, DynamicProperty dp |
889+
def.getTargetAccess() = dma and
890+
dp.getAnAccess() = dma and
891+
c.isDynamicProperty(dp) and
892+
src = def.getSource() and
893+
q = dma.getQualifier() and
894+
e = def.getExpr() and
895+
postUpdate = true
896+
)
886897
}
887898

888899
/**
@@ -894,6 +905,18 @@ private predicate fieldOrPropertyRead(Expr e1, ContentSet c, FieldOrPropertyRead
894905
c = e2.getTarget().(FieldOrProperty).getContentSet()
895906
}
896907

908+
/**
909+
* Holds if `e2` is an expression that reads the dynamic property `c` from
910+
* expression `e1`.
911+
*/
912+
private predicate dynamicPropertyRead(Expr e1, ContentSet c, DynamicMemberRead e2) {
913+
exists(DynamicPropertyContent dpc |
914+
e1 = e2.getQualifier() and
915+
dpc.getAnAccess() = e2 and
916+
c.isDynamicProperty(dpc.getName())
917+
)
918+
}
919+
897920
/**
898921
* Holds if `ce` is a collection expression that adds `src` to the collection `ce`.
899922
*/
@@ -1099,6 +1122,8 @@ private module Cached {
10991122
|
11001123
fieldOrPropertyRead(e, _, read)
11011124
or
1125+
dynamicPropertyRead(e, _, read)
1126+
or
11021127
arrayRead(e, read)
11031128
)
11041129
)
@@ -1140,6 +1165,7 @@ private module Cached {
11401165
newtype TContent =
11411166
TFieldContent(Field f) { f.isUnboundDeclaration() } or
11421167
TPropertyContent(Property p) { p.isUnboundDeclaration() } or
1168+
TDynamicPropertyContent(DynamicProperty dp) or
11431169
TElementContent() or
11441170
TSyntheticFieldContent(SyntheticField f) or
11451171
TPrimaryConstructorParameterContent(Parameter p) {
@@ -1154,12 +1180,16 @@ private module Cached {
11541180
cached
11551181
newtype TContentSet =
11561182
TSingletonContent(Content c) { not c instanceof PropertyContent } or
1157-
TPropertyContentSet(Property p) { p.isUnboundDeclaration() }
1183+
TPropertyContentSet(Property p) { p.isUnboundDeclaration() } or
1184+
TDynamicPropertyContentSet(DynamicProperty dp)
11581185

11591186
cached
11601187
newtype TContentApprox =
11611188
TFieldApproxContent(string firstChar) { firstChar = approximateFieldContent(_) } or
11621189
TPropertyApproxContent(string firstChar) { firstChar = approximatePropertyContent(_) } or
1190+
TDynamicPropertyApproxContent(string firstChar) {
1191+
firstChar = approximateDynamicPropertyContent(_)
1192+
} or
11631193
TElementApproxContent() or
11641194
TSyntheticFieldApproxContent() or
11651195
TPrimaryConstructorParameterApproxContent(string firstChar) {
@@ -2084,6 +2114,18 @@ class FieldOrProperty extends Assignable, Modifiable {
20842114
}
20852115
}
20862116

2117+
/** A string that is a reference to a late-bound target of a dynamic member access. */
2118+
class DynamicProperty extends string {
2119+
private DynamicMemberAccess dma;
2120+
2121+
DynamicProperty() { this = dma.getLateBoundTargetName() }
2122+
2123+
ContentSet getContentSet() { result.isDynamicProperty(this) }
2124+
2125+
/** Gets an access of this dynamic property. */
2126+
DynamicMemberAccess getAnAccess() { result = dma }
2127+
}
2128+
20872129
private class InstanceFieldOrProperty extends FieldOrProperty {
20882130
InstanceFieldOrProperty() { not this.isStatic() }
20892131
}
@@ -2342,6 +2384,11 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration
23422384
or
23432385
exactScope = false and
23442386
isSuccessor = true and
2387+
dynamicPropertyRead(e1, _, e2) and
2388+
scope = e2
2389+
or
2390+
exactScope = false and
2391+
isSuccessor = true and
23452392
arrayRead(e1, e2) and
23462393
scope = e2
23472394
or
@@ -2474,6 +2521,8 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
24742521
exists(ReadStepConfiguration x | hasNodePath(x, node1, node2) |
24752522
fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr())
24762523
or
2524+
dynamicPropertyRead(node1.asExpr(), c, node2.asExpr())
2525+
or
24772526
node2.asExpr().(AwaitExpr).getExpr() = node1.asExpr() and
24782527
c = getResultContent()
24792528
)
@@ -3064,6 +3113,11 @@ class ContentApprox extends TContentApprox {
30643113
this = TPropertyApproxContent(firstChar) and result = "approximated property " + firstChar
30653114
)
30663115
or
3116+
exists(string firstChar |
3117+
this = TDynamicPropertyApproxContent(firstChar) and
3118+
result = "approximated dynamic property " + firstChar
3119+
)
3120+
or
30673121
this = TElementApproxContent() and result = "element"
30683122
or
30693123
this = TSyntheticFieldApproxContent() and result = "approximated synthetic field"
@@ -3095,6 +3149,11 @@ private string approximatePropertyContent(PropertyContent pc) {
30953149
result = pc.getProperty().getName().prefix(1)
30963150
}
30973151

3152+
/** Gets a string for approximating the name of a dynamic property. */
3153+
private string approximateDynamicPropertyContent(DynamicPropertyContent dpc) {
3154+
result = dpc.getName().prefix(1)
3155+
}
3156+
30983157
/**
30993158
* Gets a string for approximating the name of a synthetic field corresponding
31003159
* to a primary constructor parameter.
@@ -3110,6 +3169,8 @@ ContentApprox getContentApprox(Content c) {
31103169
or
31113170
result = TPropertyApproxContent(approximatePropertyContent(c))
31123171
or
3172+
result = TDynamicPropertyApproxContent(approximateDynamicPropertyContent(c))
3173+
or
31133174
c instanceof ElementContent and result = TElementApproxContent()
31143175
or
31153176
c instanceof SyntheticFieldContent and result = TSyntheticFieldApproxContent()

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,23 @@ class PropertyContent extends Content, TPropertyContent {
239239
override Location getLocation() { result = p.getLocation() }
240240
}
241241

242+
/** A reference to a dynamic property. */
243+
class DynamicPropertyContent extends Content, TDynamicPropertyContent {
244+
private DynamicProperty name;
245+
246+
DynamicPropertyContent() { this = TDynamicPropertyContent(name) }
247+
248+
/** Gets an access of this dynamic property. */
249+
DynamicMemberAccess getAnAccess() { result = name.getAnAccess() }
250+
251+
override string toString() { result = "dynamic property " + name }
252+
253+
override EmptyLocation getLocation() { any() }
254+
255+
/** Gets the name that is referenced. */
256+
string getName() { result = name }
257+
}
258+
242259
/**
243260
* A reference to the index of an argument of a delegate call.
244261
*/
@@ -324,6 +341,9 @@ class ContentSet extends TContentSet {
324341
*/
325342
predicate isProperty(Property p) { this = TPropertyContentSet(p) }
326343

344+
/** Holds if this content set represents the dynamic property `name`. */
345+
predicate isDynamicProperty(string name) { this = TDynamicPropertyContentSet(name) }
346+
327347
/**
328348
* Holds if this content set represents the `i`th argument of a delegate call.
329349
*/
@@ -348,6 +368,8 @@ class ContentSet extends TContentSet {
348368
this.isSingleton(result)
349369
or
350370
this.isProperty(result.(PropertyContent).getProperty())
371+
or
372+
this.isDynamicProperty(result.(DynamicPropertyContent).getName())
351373
}
352374

353375
/** Gets a content that may be read from when reading from this set. */
@@ -362,6 +384,17 @@ class ContentSet extends TContentSet {
362384
or
363385
overridesOrImplementsSourceDecl(p1, p2)
364386
)
387+
or
388+
exists(FieldOrProperty p |
389+
this = p.getContentSet() and
390+
result.(DynamicPropertyContent).getName() = p.getName()
391+
)
392+
or
393+
this.isDynamicProperty([
394+
result.(DynamicPropertyContent).getName(),
395+
result.(PropertyContent).getProperty().getName(),
396+
result.(FieldContent).getField().getName()
397+
])
365398
}
366399

367400
/** Gets a textual representation of this content set. */
@@ -375,6 +408,11 @@ class ContentSet extends TContentSet {
375408
this.isProperty(p) and
376409
result = "property " + p.getName()
377410
)
411+
or
412+
exists(string name |
413+
this.isDynamicProperty(name) and
414+
result = "dynamic property " + name
415+
)
378416
}
379417

380418
/** Gets the location of this content set. */
@@ -388,5 +426,8 @@ class ContentSet extends TContentSet {
388426
this.isProperty(p) and
389427
result = p.getLocation()
390428
)
429+
or
430+
this.isDynamicProperty(_) and
431+
result instanceof EmptyLocation
391432
}
392433
}

0 commit comments

Comments
 (0)