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
@@ -269,27 +328,57 @@ private DataFlow::Node getSourceFromCallable(Callable callable, AccessPathToken
269328 result .isReceiverParameter ( callable )
270329}
271330
331+ /**
332+ * Gets the source from the property `access` specified by `path`.
333+ */
334+ bindingset [ access, path]
335+ private DataFlow:: Node getSourceFromPropertyAccess ( MemberAccess access , AccessPath path ) {
336+ path = "" and
337+ result .isResultValue ( access )
338+ }
339+
340+ /**
341+ * Gets the sink from the property `access` specified by `path`.
342+ */
343+ bindingset [ access, path]
344+ private DataFlow:: Node getSinkFromPropertyAccess ( MemberAccess access , AccessPath path ) {
345+ path = "PostUpdate" and
346+ (
347+ // The value being assigned to the property, as in `x.prop = value`
348+ result .isIncomingValue ( access )
349+ or
350+ // The property value after being mutated in-place, as in `x.prop.append(value)`
351+ result .isPostUpdate ( access )
352+ )
353+ }
354+
272355private predicate normalizedSourceModel (
273356 Selector selector , AccessPath output , string kind , string provenance
274357) {
275- exists (
276- string type , boolean subtypes , string rawName , string name , string argLabels , string argTypes
358+ exists ( string type , boolean subtypes , string rawName , string argTypes |
359+ legacySourceModel ( _ , type , subtypes , rawName , argTypes , _ , output , kind , provenance )
277360 |
278- legacySourceModel ( _, type , subtypes , rawName , argTypes , _, output , kind , provenance ) and
279- parsedRawMethodName ( rawName , name , argLabels ) and
280- selector = MkSelector ( type , subtypes , name , argLabels , argTypes )
361+ exists ( string name , string argLabels |
362+ parsedRawMethodName ( rawName , name , argLabels ) and
363+ selector = MkCallSelector ( type , subtypes , name , argLabels , argTypes )
364+ )
365+ or
366+ selector = MkPropertySelector ( type , subtypes , rawName )
281367 )
282368}
283369
284370private predicate normalizedSinkModel (
285371 Selector selector , AccessPath output , string kind , string provenance
286372) {
287- exists (
288- string type , boolean subtypes , string rawName , string name , string argLabels , string argTypes
373+ exists ( string type , boolean subtypes , string rawName , string argTypes |
374+ legacySinkModel ( _ , type , subtypes , rawName , argTypes , _ , output , kind , provenance )
289375 |
290- legacySinkModel ( _, type , subtypes , rawName , argTypes , _, output , kind , provenance ) and
291- parsedRawMethodName ( rawName , name , argLabels ) and
292- selector = MkSelector ( type , subtypes , name , argLabels , argTypes )
376+ exists ( string name , string argLabels |
377+ parsedRawMethodName ( rawName , name , argLabels ) and
378+ selector = MkCallSelector ( type , subtypes , name , argLabels , argTypes )
379+ )
380+ or
381+ selector = MkPropertySelector ( type , subtypes , rawName )
293382 )
294383}
295384
@@ -301,7 +390,7 @@ predicate normalizedSummaryModel(
301390 |
302391 legacySummaryModel ( _, type , subtypes , rawName , argTypes , _, input , output , kind , provenance ) and
303392 parsedRawMethodName ( rawName , name , argLabels ) and
304- selector = MkSelector ( type , subtypes , name , argLabels , argTypes )
393+ selector = MkCallSelector ( type , subtypes , name , argLabels , argTypes )
305394 )
306395}
307396
@@ -321,6 +410,11 @@ DataFlow::Node getASource(string kind, string provenance) {
321410 selector .matchesCallable ( callable ) and
322411 result = getSourceFromCallable ( callable , output )
323412 )
413+ or
414+ exists ( MemberAccess access |
415+ selector .matchesPropertyAccess ( access ) and
416+ result = getSourceFromPropertyAccess ( access , output )
417+ )
324418 )
325419}
326420
@@ -340,6 +434,11 @@ DataFlow::Node getASink(string kind, string provenance) {
340434 selector .matchesCallable ( callable ) and
341435 result = getSinkFromCallable ( callable , input )
342436 )
437+ or
438+ exists ( MemberAccess access |
439+ selector .matchesPropertyAccess ( access ) and
440+ result = getSinkFromPropertyAccess ( access , input )
441+ )
343442 )
344443}
345444
0 commit comments