@@ -150,20 +150,50 @@ module SourceSinkInterpretationInput implements
150150 }
151151
152152 private newtype TSourceOrSinkElement =
153- TEntityElement ( Entity e ) or
153+ TMethodEntityElement ( Method m , string pkg , string type , boolean subtypes ) {
154+ m .hasQualifiedName ( pkg , type , _) and subtypes = [ true , false ]
155+ } or
156+ TFieldEntityElement ( Field f , string pkg , string type , boolean subtypes ) {
157+ f .hasQualifiedName ( pkg , type , _) and subtypes = [ true , false ]
158+ } or
159+ TOtherEntityElement ( Entity e ) {
160+ not e instanceof Method and
161+ not e instanceof Field
162+ } or
154163 TAstElement ( AstNode n )
155164
156165 /** An element representable by CSV modeling. */
157166 class SourceOrSinkElement extends TSourceOrSinkElement {
158167 /** Gets this source or sink element as an entity, if it is one. */
159- Entity asEntity ( ) { this = TEntityElement ( result ) }
168+ Entity asEntity ( ) {
169+ this = TMethodEntityElement ( result , _, _, _) or
170+ this = TFieldEntityElement ( result , _, _, _) or
171+ this = TOtherEntityElement ( result )
172+ }
160173
161174 /** Gets this source or sink element as an AST node, if it is one. */
162175 AstNode asAstNode ( ) { this = TAstElement ( result ) }
163176
177+ /**
178+ * Holds if this source or sink element is a method that was specified
179+ * with the given values for `pkg`, `type` and `subtypes`.
180+ */
181+ predicate hasTypeInfo ( string pkg , string type , boolean subtypes ) {
182+ this = TMethodEntityElement ( _, pkg , type , subtypes ) or
183+ this = TFieldEntityElement ( _, pkg , type , subtypes )
184+ }
185+
164186 /** Gets a textual representation of this source or sink element. */
165187 string toString ( ) {
188+ not this .hasTypeInfo ( _, _, _) and
166189 result = "element representing " + [ this .asEntity ( ) .toString ( ) , this .asAstNode ( ) .toString ( ) ]
190+ or
191+ exists ( string pkg , string name , boolean subtypes |
192+ this .hasTypeInfo ( pkg , name , subtypes ) and
193+ result =
194+ "element representing " + this .asEntity ( ) .toString ( ) + " with receiver type " + pkg + "." +
195+ name + " and subtypes=" + subtypes
196+ )
167197 }
168198
169199 /** Gets the location of this element. */
@@ -203,7 +233,17 @@ module SourceSinkInterpretationInput implements
203233
204234 /** Gets the target of this call, if any. */
205235 SourceOrSinkElement getCallTarget ( ) {
206- result .asEntity ( ) = this .asCall ( ) .getNode ( ) .( DataFlow:: CallNode ) .getTarget ( )
236+ exists ( DataFlow:: CallNode cn , Function callTarget |
237+ cn = this .asCall ( ) .getNode ( ) and
238+ callTarget = cn .getTarget ( )
239+ |
240+ result .asEntity ( ) = callTarget and
241+ (
242+ not callTarget instanceof Method
243+ or
244+ ensureCorrectTypeInfo ( result , cn .getReceiver ( ) )
245+ )
246+ )
207247 }
208248
209249 /** Gets a textual representation of this node. */
@@ -228,6 +268,90 @@ module SourceSinkInterpretationInput implements
228268 }
229269 }
230270
271+ private predicate ensureCorrectTypeInfo ( SourceOrSinkElement sse , DataFlow:: Node recv ) {
272+ (
273+ exists ( DataFlow:: CallNode cn | cn .getReceiver ( ) = recv and cn .getTarget ( ) = sse .asEntity ( ) )
274+ or
275+ exists ( DataFlow:: FieldReadNode frn | frn .getBase ( ) = recv and frn .getField ( ) = sse .asEntity ( ) )
276+ or
277+ exists ( DataFlow:: Write fw | fw .writesField ( recv , sse .asEntity ( ) , _) )
278+ ) and
279+ exists ( string pkg , string typename , boolean subtypes , Type syntacticRecvBaseType |
280+ sse .hasTypeInfo ( pkg , typename , subtypes ) and
281+ syntacticRecvBaseType = lookThroughPointerType ( getSyntacticRecv ( recv ) .getType ( ) )
282+ |
283+ subtypes = [ true , false ] and
284+ syntacticRecvBaseType .hasQualifiedName ( pkg , typename )
285+ or
286+ subtypes = true and
287+ (
288+ // `syntacticRecvBaseType`'s underlying type might be an interface type and `sse`
289+ // might be a method defined on an interface which is a subtype of it.
290+ exists ( Type t |
291+ t = syntacticRecvBaseType .getUnderlyingType ( ) .( InterfaceType ) .getAnEmbeddedInterface ( ) and
292+ t .hasQualifiedName ( pkg , typename ) and
293+ sse .asEntity ( ) .( Method ) .hasQualifiedName ( pkg , typename , _)
294+ )
295+ or
296+ // `syntacticRecvBaseType`'s underlying type might be a struct type and `sse`
297+ // might be a promoted method or field.
298+ exists ( StructType st , Field field1 , Field field2 , int depth1 , int depth2 , Type t1 , Type t2 |
299+ st = syntacticRecvBaseType .getUnderlyingType ( ) and
300+ field1 = st .getFieldAtDepth ( _, depth1 ) and
301+ field2 = st .getFieldAtDepth ( _, depth2 ) and
302+ t1 = lookThroughPointerType ( field1 .getType ( ) ) and
303+ t2 = lookThroughPointerType ( field2 .getType ( ) ) and
304+ (
305+ field1 = field2
306+ or
307+ field2 = t1 .getUnderlyingType ( ) .( StructType ) .getFieldAtDepth ( _, depth2 - depth1 - 1 )
308+ ) and
309+ matchTypeInfo ( sse , t1 )
310+ |
311+ sse .asEntity ( ) .( Method ) .getReceiverBaseType ( ) = t2
312+ or
313+ sse .asEntity ( ) .( Field ) .getDeclaringType ( ) = t2 .getUnderlyingType ( )
314+ )
315+ )
316+ )
317+ }
318+
319+ private DataFlow:: Node getSyntacticRecv ( DataFlow:: Node n ) {
320+ exists ( DataFlow:: Node n2 |
321+ // look through implicit dereference, if there is one
322+ not exists ( n .asInstruction ( ) .( IR:: EvalImplicitDerefInstruction ) .getOperand ( ) ) and
323+ n2 = n
324+ or
325+ n2 .asExpr ( ) = n .asInstruction ( ) .( IR:: EvalImplicitDerefInstruction ) .getOperand ( )
326+ |
327+ result = skipImplicitFieldReads ( n2 )
328+ )
329+ }
330+
331+ private DataFlow:: Node skipImplicitFieldReads ( DataFlow:: Node n ) {
332+ not exists ( getImplicitFieldReadInstruction ( n ) ) and result = n
333+ or
334+ result = skipImplicitFieldReads ( getImplicitFieldReadInstruction ( n ) )
335+ }
336+
337+ pragma [ inline]
338+ private DataFlow:: Node getImplicitFieldReadInstruction ( DataFlow:: Node n ) {
339+ result .asInstruction ( ) =
340+ n .( DataFlow:: InstructionNode )
341+ .asInstruction ( )
342+ .( IR:: ImplicitFieldReadInstruction )
343+ .getBaseInstruction ( )
344+ }
345+
346+ bindingset [ sse, t]
347+ pragma [ inline_late]
348+ private predicate matchTypeInfo ( SourceOrSinkElement sse , Type t ) {
349+ exists ( string pkg , string typename |
350+ sse .hasTypeInfo ( pkg , typename , true ) and
351+ t .hasQualifiedName ( pkg , typename )
352+ )
353+ }
354+
231355 /** Provides additional sink specification logic. */
232356 bindingset [ c]
233357 predicate interpretOutput ( string c , InterpretNode mid , InterpretNode node ) {
@@ -244,8 +368,11 @@ module SourceSinkInterpretationInput implements
244368 ( c = "Parameter" or c = "" ) and
245369 node .asNode ( ) .asParameter ( ) = e .asEntity ( )
246370 or
247- c = "" and
248- n .( DataFlow:: FieldReadNode ) .getField ( ) = e .asEntity ( )
371+ exists ( DataFlow:: FieldReadNode frn | frn = n |
372+ c = "" and
373+ frn .getField ( ) = e .asEntity ( ) and
374+ ensureCorrectTypeInfo ( e , frn .getBase ( ) )
375+ )
249376 )
250377 }
251378
@@ -259,10 +386,13 @@ module SourceSinkInterpretationInput implements
259386 mid .asCallable ( ) = getNodeEnclosingCallable ( ret )
260387 )
261388 or
262- exists ( DataFlow:: Write fw , Field f |
389+ exists ( SourceOrSinkElement e , DataFlow:: Write fw , DataFlow:: Node base , Field f |
390+ e = mid .asElement ( ) and
391+ f = e .asEntity ( )
392+ |
263393 c = "" and
264- f = mid . asElement ( ) . asEntity ( ) and
265- fw . writesField ( _ , f , node . asNode ( ) )
394+ fw . writesField ( base , f , node . asNode ( ) ) and
395+ ensureCorrectTypeInfo ( e , base )
266396 )
267397 }
268398}
0 commit comments