1010import java .util .List ;
1111import java .util .Map ;
1212import java .util .Set ;
13+ import java .util .concurrent .ExecutionException ;
14+ import java .util .stream .Collectors ;
1315
1416import org .slf4j .Logger ;
1517import org .slf4j .LoggerFactory ;
1921
2022import heros .solver .IDESolver ;
2123import heros .solver .Pair ;
24+ import soot .Hierarchy ;
2225import soot .Scene ;
2326import soot .SootClass ;
2427import soot .SootField ;
@@ -111,19 +114,35 @@ public static enum SourceType {
111114 protected SootMethod currentSource = null ;
112115 protected IValueProvider valueProvider = new SimpleConstantValueProvider ();
113116
114- protected final LoadingCache <SootClass , Collection <SootClass >> interfacesOf = IDESolver .DEFAULT_CACHE_BUILDER
117+ protected final LoadingCache <SootClass , Collection <SootClass >> parentClassesAndInterfaces = IDESolver .DEFAULT_CACHE_BUILDER
115118 .build (new CacheLoader <SootClass , Collection <SootClass >>() {
116119
117120 @ Override
118121 public Collection <SootClass > load (SootClass sc ) throws Exception {
119- Set <SootClass > set = new HashSet <SootClass >(sc .getInterfaceCount ());
120- for (SootClass i : sc .getInterfaces ()) {
121- set .add (i );
122- set .addAll (interfacesOf .getUnchecked (i ));
123- }
124- if (sc .hasSuperclass ())
125- set .addAll (interfacesOf .getUnchecked (sc .getSuperclass ()));
126- return set ;
122+ Hierarchy h = Scene .v ().getActiveHierarchy ();
123+
124+ // Don't try to find sources or sinks in irrelevant classes
125+ if (sc .isPhantom () || sc .hasTag (SimulatedCodeElementTag .TAG_NAME ))
126+ return Collections .emptySet ();
127+
128+ // For interfaces, we compute the transitive list of parent interfaces
129+ if (sc .isInterface ())
130+ return h .getSuperinterfacesOfIncluding (sc );
131+
132+ // We need to collect all interfaces of all superclasses. First, we take the
133+ // superclasses, and then we call this method recursively on all interfaces
134+ // declared on these classes.
135+ Set <SootClass > res = new HashSet <>();
136+ res .addAll (h .getSuperclassesOfIncluding (sc ));
137+
138+ res .addAll (res .stream ().flatMap (c -> c .getInterfaces ().stream ()).flatMap (i -> {
139+ try {
140+ return parentClassesAndInterfaces .get (i ).stream ();
141+ } catch (ExecutionException e ) {
142+ throw new RuntimeException (e );
143+ }
144+ }).collect (Collectors .toSet ()));
145+ return res ;
127146 }
128147
129148 });
@@ -227,7 +246,8 @@ protected ISourceSinkDefinition getSinkDefinition(Stmt sCallSite, InfoflowManage
227246 final String subSig = callee .getSubSignature ();
228247
229248 // Check whether we have any of the interfaces on the list
230- for (SootClass i : interfacesOf .getUnchecked (sCallSite .getInvokeExpr ().getMethod ().getDeclaringClass ())) {
249+ for (SootClass i : parentClassesAndInterfaces
250+ .getUnchecked (sCallSite .getInvokeExpr ().getMethod ().getDeclaringClass ())) {
231251 if (i .declaresMethod (subSig )) {
232252 ISourceSinkDefinition def = this .sinkMethods .get (i .getMethod (subSig ));
233253 if (def != null )
@@ -242,16 +262,7 @@ protected ISourceSinkDefinition getSinkDefinition(Stmt sCallSite, InfoflowManage
242262 return def ;
243263 }
244264
245- // If the target method is in a phantom class, we scan the hierarchy
246- // upwards to see whether we have a sink definition for a parent
247- // class
248- if (callee .getDeclaringClass ().isPhantom ()) {
249- ISourceSinkDefinition def = findDefinitionInHierarchy (callee , this .sinkMethods );
250- if (def != null )
251- return def ;
252- }
253265 return null ;
254-
255266 } else if (sCallSite instanceof AssignStmt ) {
256267 // Check if the target is a sink field
257268 AssignStmt assignStmt = (AssignStmt ) sCallSite ;
@@ -291,7 +302,7 @@ protected ISourceSinkDefinition getInverseSource(Stmt sCallSite, InfoflowManager
291302
292303 // Check whether we have any of the interfaces on the list
293304 final String subSig = callee .getSubSignature ();
294- for (SootClass i : interfacesOf .getUnchecked (callee .getDeclaringClass ())) {
305+ for (SootClass i : parentClassesAndInterfaces .getUnchecked (callee .getDeclaringClass ())) {
295306 SootMethod m = i .getMethodUnsafe (subSig );
296307 if (m != null ) {
297308 def = getSourceDefinition (m );
@@ -306,15 +317,6 @@ protected ISourceSinkDefinition getInverseSource(Stmt sCallSite, InfoflowManager
306317 if (def != null )
307318 return def ;
308319 }
309-
310- // If the target method is in a phantom class, we scan the hierarchy
311- // upwards
312- // to see whether we have a sink definition for a parent class
313- if (callee .getDeclaringClass ().isPhantom ()) {
314- def = findDefinitionInHierarchy (callee , this .sourceMethods );
315- if (def != null )
316- return def ;
317- }
318320 }
319321
320322 // This call might read out sensitive data from the UI
@@ -336,42 +338,6 @@ protected ISourceSinkDefinition getInverseSource(Stmt sCallSite, InfoflowManager
336338 return null ;
337339 }
338340
339- /**
340- * Scans the hierarchy of the class containing the given method to find any
341- * implementations of the same method further up in the hierarchy for which
342- * there is a SourceSinkDefinition in the given map
343- *
344- * @param callee The method for which to look for a SourceSinkDefinition
345- * @param map A map from methods to their corresponding SourceSinkDefinitions
346- * @return A SourceSinKDefinition for an implementation of the given method
347- * somewhere up in the class hiearchy if it exists, otherwise null.
348- */
349- private static ISourceSinkDefinition findDefinitionInHierarchy (SootMethod callee ,
350- Map <SootMethod , ISourceSinkDefinition > map ) {
351- final String subSig = callee .getSubSignature ();
352- SootClass curClass = callee .getDeclaringClass ();
353- while (curClass != null ) {
354- // Does the current class declare the requested method?
355- SootMethod curMethod = curClass .getMethodUnsafe (subSig );
356- if (curMethod != null ) {
357- ISourceSinkDefinition def = map .get (curMethod );
358- if (def != null ) {
359- // Patch the map to contain a direct link
360- map .put (callee , def );
361- return def ;
362- }
363- }
364-
365- // Try the next class up the hierarchy
366- if (curClass .hasSuperclass () && (curClass .isPhantom () || callee .hasTag (SimulatedCodeElementTag .TAG_NAME )))
367- curClass = curClass .getSuperclass ();
368- else
369- curClass = null ;
370- }
371-
372- return null ;
373- }
374-
375341 @ Override
376342 public SinkInfo getSinkInfo (Stmt sCallSite , InfoflowManager manager , AccessPath ap ) {
377343 // Do not look for sinks in excluded methods
@@ -582,7 +548,7 @@ protected ISourceSinkDefinition getSource(Stmt sCallSite, IInfoflowCFG cfg) {
582548
583549 // Check whether we have any of the interfaces on the list
584550 final String subSig = callee .getSubSignature ();
585- for (SootClass i : interfacesOf .getUnchecked (callee .getDeclaringClass ())) {
551+ for (SootClass i : parentClassesAndInterfaces .getUnchecked (callee .getDeclaringClass ())) {
586552 SootMethod m = i .getMethodUnsafe (subSig );
587553 if (m != null ) {
588554 def = getSourceDefinition (m );
@@ -597,15 +563,6 @@ protected ISourceSinkDefinition getSource(Stmt sCallSite, IInfoflowCFG cfg) {
597563 if (def != null )
598564 return def ;
599565 }
600-
601- // If the target method is in a phantom class, we scan the hierarchy
602- // upwards
603- // to see whether we have a sink definition for a parent class
604- if (callee .getDeclaringClass ().isPhantom () || callee .hasTag (SimulatedCodeElementTag .TAG_NAME )) {
605- def = findDefinitionInHierarchy (callee , this .sourceMethods );
606- if (def != null )
607- return def ;
608- }
609566 }
610567
611568 // This call might read out sensitive data from the UI
@@ -651,7 +608,7 @@ protected ISourceSinkDefinition getInverseSink(Stmt sCallSite, IInfoflowCFG cfg)
651608 final String subSig = callee .getSubSignature ();
652609
653610 // Check whether we have any of the interfaces on the list
654- for (SootClass i : interfacesOf .getUnchecked (callee .getDeclaringClass ())) {
611+ for (SootClass i : parentClassesAndInterfaces .getUnchecked (callee .getDeclaringClass ())) {
655612 if (i .declaresMethod (subSig )) {
656613 ISourceSinkDefinition def = this .sinkMethods .get (i .getMethod (subSig ));
657614 if (def != null )
@@ -666,16 +623,7 @@ protected ISourceSinkDefinition getInverseSink(Stmt sCallSite, IInfoflowCFG cfg)
666623 return def ;
667624 }
668625
669- // If the target method is in a phantom class, we scan the hierarchy
670- // upwards to see whether we have a sink definition for a parent
671- // class
672- if (callee .getDeclaringClass ().isPhantom () || callee .hasTag (SimulatedCodeElementTag .TAG_NAME )) {
673- ISourceSinkDefinition def = findDefinitionInHierarchy (callee , this .sinkMethods );
674- if (def != null )
675- return def ;
676- }
677626 return null ;
678-
679627 } else if (sCallSite instanceof AssignStmt ) {
680628 // Check if the target is a sink field
681629 AssignStmt assignStmt = (AssignStmt ) sCallSite ;
0 commit comments