44
55private import unified
66private import codeql.dataflow.internal.AccessPathSyntax
7+ private import codeql.unified.internal.typeinference.TypeInference as T
78
89extensible predicate legacySourceModel (
910 string namespace , string type , boolean subtypes , string name , string signature , string ext ,
@@ -29,7 +30,6 @@ private predicate modelContainsMethodName(string name) {
2930}
3031
3132private predicate parsedRawMethodName ( string rawName , string name , string argLabels ) {
32- // NOTE: We only support method names at the moment, not property names like `String.count`.
3333 modelContainsMethodName ( rawName ) and
3434 exists ( string regex |
3535 regex = "([^(]+)\\((.*)\\)" and
@@ -123,8 +123,36 @@ private predicate callableSelector(
123123 )
124124}
125125
126+ /** Holds if `name` from a model refers to a property, such as `count` in `String.count`. */
127+ private predicate isRawPropertyName ( string name ) {
128+ modelContainsMethodName ( name ) and
129+ not name .matches ( "%(%" )
130+ }
131+
132+ /** Holds if `cls` is named `type` or, if `subtypes` is true, is a subclass of `type`. */
133+ bindingset [ cls, type]
134+ private predicate classMatchesType ( ClassLikeDeclaration cls , string type , boolean subtypes ) {
135+ cls .getQualifiedName ( ) = type and subtypes = [ true , false ]
136+ or
137+ isSubclassOfType ( cls , type ) and subtypes = true
138+ }
139+
140+ /**
141+ * Holds if `access` may be an access to the property `name`, and its base has the inferred
142+ * type `cls`.
143+ */
144+ pragma [ nomagic]
145+ private predicate propertyAccessSelector (
146+ MemberAccess access , ClassLikeDeclaration cls , string name
147+ ) {
148+ name = access .getMemberName ( ) and
149+ name = any ( Selector s ) .getPropertyName ( ) and
150+ not access = any ( CallExpr call ) .getCallee ( ) and
151+ cls = T:: inferBaseType ( access ) .asClass ( )
152+ }
153+
126154private newtype TSelector =
127- MkSelector ( string type , boolean subtypes , string name , string argLabels , string argTypes ) {
155+ MkCallSelector ( string type , boolean subtypes , string name , string argLabels , string argTypes ) {
128156 exists ( string rawName |
129157 legacySourceModel ( _, type , subtypes , rawName , argTypes , _, _, _, _)
130158 or
@@ -134,21 +162,38 @@ private newtype TSelector =
134162 |
135163 parsedRawMethodName ( rawName , name , argLabels )
136164 )
165+ } or
166+ MkPropertySelector ( string type , boolean subtypes , string name ) {
167+ (
168+ legacySourceModel ( _, type , subtypes , name , _, _, _, _, _)
169+ or
170+ legacySinkModel ( _, type , subtypes , name , _, _, _, _, _)
171+ ) and
172+ isRawPropertyName ( name )
137173 }
138174
139175/**
140- * A tuple from a model that identifies call sites.
176+ * A tuple from a model that identifies call sites, callables, or property accesses .
141177 */
142178class Selector extends TSelector {
143- string getTypeString ( ) { this = MkSelector ( result , _, _, _, _) }
179+ string getTypeString ( ) {
180+ this = MkCallSelector ( result , _, _, _, _) or this = MkPropertySelector ( result , _, _)
181+ }
182+
183+ boolean getSubtypesFlag ( ) {
184+ this = MkCallSelector ( _, result , _, _, _) or this = MkPropertySelector ( _, result , _)
185+ }
144186
145- boolean getSubtypesFlag ( ) { this = MkSelector ( _, result , _, _, _) }
187+ string getName ( ) {
188+ this = MkCallSelector ( _, _, result , _, _) or this = MkPropertySelector ( _, _, result )
189+ }
146190
147- string getName ( ) { this = MkSelector ( _, _, result , _, _) }
191+ /** Gets the property name, if this is a property selector. */
192+ string getPropertyName ( ) { this = MkPropertySelector ( _, _, result ) }
148193
149- string getArgLabels ( ) { this = MkSelector ( _, _, _, result , _) }
194+ string getArgLabels ( ) { this = MkCallSelector ( _, _, _, result , _) }
150195
151- string getArgTypes ( ) { this = MkSelector ( _, _, _, _, result ) }
196+ string getArgTypes ( ) { this = MkCallSelector ( _, _, _, _, result ) }
152197
153198 private string ppSubtypes ( ) {
154199 if this .getSubtypesFlag ( ) = true then result = "+" else result = ""
@@ -158,19 +203,21 @@ class Selector extends TSelector {
158203 result =
159204 this .getTypeString ( ) + this .ppSubtypes ( ) + "." + this .getName ( ) + "(" + this .getArgLabels ( ) +
160205 ")" + this .getArgTypes ( )
206+ or
207+ result = this .getTypeString ( ) + this .ppSubtypes ( ) + "." + this .getPropertyName ( )
161208 }
162209
163210 /** Holds if `name,argLabels` should be used to join with `methodCallSelector`. */
164211 pragma [ nomagic]
165212 private predicate matchesMethodCallSelector ( string name , string argLabels ) {
166- this = MkSelector ( _, _, name , argLabels , _) and
213+ this = MkCallSelector ( _, _, name , argLabels , _) and
167214 name != "init"
168215 }
169216
170217 /** Holds if `name,argLabels` should be used to join with `constructorCallSelector`. */
171218 pragma [ nomagic]
172219 private predicate matchesConstructorCallSelector ( string name , string argLabels ) {
173- this = MkSelector ( name , _, "init" , argLabels , _)
220+ this = MkCallSelector ( name , _, "init" , argLabels , _)
174221 }
175222
176223 predicate matchesCall ( CallExpr call ) {
@@ -186,7 +233,19 @@ class Selector extends TSelector {
186233 predicate matchesCallable ( Callable callable ) {
187234 exists ( string type , string name , string argLabels |
188235 callableSelector ( callable , type , name , argLabels ) and
189- this = MkSelector ( type , true , name , argLabels , _)
236+ this = MkCallSelector ( type , true , name , argLabels , _)
237+ )
238+ }
239+
240+ /**
241+ * Holds if `access` is an access to the property identified by this selector, as determined
242+ * by the inferred type of its base.
243+ */
244+ predicate matchesPropertyAccess ( MemberAccess access ) {
245+ exists ( ClassLikeDeclaration cls , string type , boolean subtypes , string name |
246+ this = MkPropertySelector ( type , subtypes , name ) and
247+ propertyAccessSelector ( access , cls , name ) and
248+ classMatchesType ( cls , type , subtypes )
190249 )
191250 }
192251
@@ -267,27 +326,57 @@ private DataFlow::Node getSourceFromCallable(Callable callable, AccessPathToken
267326 result .isReceiverParameter ( callable )
268327}
269328
329+ /**
330+ * Gets the source from the property `access` specified by `path`.
331+ */
332+ bindingset [ access, path]
333+ private DataFlow:: Node getSourceFromPropertyAccess ( MemberAccess access , AccessPath path ) {
334+ path = "" and
335+ result .isResultValue ( access )
336+ }
337+
338+ /**
339+ * Gets the sink from the property `access` specified by `path`.
340+ */
341+ bindingset [ access, path]
342+ private DataFlow:: Node getSinkFromPropertyAccess ( MemberAccess access , AccessPath path ) {
343+ path = "PostUpdate" and
344+ (
345+ // The value being assigned to the property, as in `x.prop = value`
346+ result .isIncomingValue ( access )
347+ or
348+ // The property value after being mutated in-place, as in `x.prop.append(value)`
349+ result .isPostUpdate ( access )
350+ )
351+ }
352+
270353private predicate normalizedSourceModel (
271354 Selector selector , AccessPath output , string kind , string provenance
272355) {
273- exists (
274- string type , boolean subtypes , string rawName , string name , string argLabels , string argTypes
356+ exists ( string type , boolean subtypes , string rawName , string argTypes |
357+ legacySourceModel ( _ , type , subtypes , rawName , argTypes , _ , output , kind , provenance )
275358 |
276- legacySourceModel ( _, type , subtypes , rawName , argTypes , _, output , kind , provenance ) and
277- parsedRawMethodName ( rawName , name , argLabels ) and
278- selector = MkSelector ( type , subtypes , name , argLabels , argTypes )
359+ exists ( string name , string argLabels |
360+ parsedRawMethodName ( rawName , name , argLabels ) and
361+ selector = MkCallSelector ( type , subtypes , name , argLabels , argTypes )
362+ )
363+ or
364+ selector = MkPropertySelector ( type , subtypes , rawName )
279365 )
280366}
281367
282368private predicate normalizedSinkModel (
283369 Selector selector , AccessPath output , string kind , string provenance
284370) {
285- exists (
286- string type , boolean subtypes , string rawName , string name , string argLabels , string argTypes
371+ exists ( string type , boolean subtypes , string rawName , string argTypes |
372+ legacySinkModel ( _ , type , subtypes , rawName , argTypes , _ , output , kind , provenance )
287373 |
288- legacySinkModel ( _, type , subtypes , rawName , argTypes , _, output , kind , provenance ) and
289- parsedRawMethodName ( rawName , name , argLabels ) and
290- selector = MkSelector ( type , subtypes , name , argLabels , argTypes )
374+ exists ( string name , string argLabels |
375+ parsedRawMethodName ( rawName , name , argLabels ) and
376+ selector = MkCallSelector ( type , subtypes , name , argLabels , argTypes )
377+ )
378+ or
379+ selector = MkPropertySelector ( type , subtypes , rawName )
291380 )
292381}
293382
@@ -299,7 +388,7 @@ predicate normalizedSummaryModel(
299388 |
300389 legacySummaryModel ( _, type , subtypes , rawName , argTypes , _, input , output , kind , provenance ) and
301390 parsedRawMethodName ( rawName , name , argLabels ) and
302- selector = MkSelector ( type , subtypes , name , argLabels , argTypes )
391+ selector = MkCallSelector ( type , subtypes , name , argLabels , argTypes )
303392 )
304393}
305394
@@ -319,6 +408,11 @@ DataFlow::Node getASource(string kind, string provenance) {
319408 selector .matchesCallable ( callable ) and
320409 result = getSourceFromCallable ( callable , output )
321410 )
411+ or
412+ exists ( MemberAccess access |
413+ selector .matchesPropertyAccess ( access ) and
414+ result = getSourceFromPropertyAccess ( access , output )
415+ )
322416 )
323417}
324418
@@ -338,6 +432,11 @@ DataFlow::Node getASink(string kind, string provenance) {
338432 selector .matchesCallable ( callable ) and
339433 result = getSinkFromCallable ( callable , input )
340434 )
435+ or
436+ exists ( MemberAccess access |
437+ selector .matchesPropertyAccess ( access ) and
438+ result = getSinkFromPropertyAccess ( access , input )
439+ )
341440 )
342441}
343442
0 commit comments