1616import soot .jimple .infoflow .methodSummary .data .provider .IMethodSummaryProvider ;
1717import soot .jimple .infoflow .methodSummary .data .summary .ClassMethodSummaries ;
1818import soot .jimple .infoflow .methodSummary .data .summary .ClassSummaries ;
19+ import soot .jimple .infoflow .util .ByReferenceBoolean ;
1920
2021/**
2122 * A resolver for finding all applicable summaries for a given method call
@@ -35,32 +36,44 @@ public SummaryResponse load(SummaryQuery query) throws Exception {
3536 final SootClass declaredClass = query .declaredClass ;
3637 final String methodSig = query .subsignature ;
3738 final ClassSummaries classSummaries = new ClassSummaries ();
38- boolean isClassSupported = false ;
39+ boolean directHit = false ;
40+ ByReferenceBoolean isClassSupported = new ByReferenceBoolean (false );
3941
4042 // Get the flows in the target method
4143 if (calleeClass != null )
42- isClassSupported = getSummaries (methodSig , classSummaries , calleeClass );
44+ directHit = getSummaries (methodSig , classSummaries , calleeClass , isClassSupported );
4345
4446 // If we haven't found any summaries, we look at the class from the declared
4547 // type at the call site
46- if (declaredClass != null && !isClassSupported )
47- isClassSupported = getSummaries (methodSig , classSummaries , declaredClass );
48+ if (declaredClass != null && !directHit )
49+ directHit = getSummaries (methodSig , classSummaries , declaredClass , isClassSupported );
4850
4951 // If we still don't have anything, we must try the hierarchy. Since this
5052 // best-effort approach can be fairly imprecise, it is our last resort.
51- if (!isClassSupported && calleeClass != null )
52- isClassSupported = getSummariesHierarchy (methodSig , classSummaries , calleeClass );
53- if (declaredClass != null && !isClassSupported )
54- isClassSupported = getSummariesHierarchy (methodSig , classSummaries , declaredClass );
55-
56- if (isClassSupported ) {
57- if (classSummaries . isEmpty ())
58- return SummaryResponse . EMPTY_BUT_SUPPORTED ;
59- return new SummaryResponse ( classSummaries , isClassSupported ) ;
60- } else
53+ if (!directHit && calleeClass != null )
54+ directHit = getSummariesHierarchy (methodSig , classSummaries , calleeClass , isClassSupported );
55+ if (declaredClass != null && !directHit )
56+ directHit = getSummariesHierarchy (methodSig , classSummaries , declaredClass , isClassSupported );
57+
58+ if (directHit && ! classSummaries . isEmpty ())
59+ return new SummaryResponse (classSummaries , true );
60+ else if ( directHit || isClassSupported . value )
61+ return SummaryResponse . EMPTY_BUT_SUPPORTED ;
62+ else
6163 return SummaryResponse .NOT_SUPPORTED ;
6264 }
6365
66+ private void updateClassExclusive (ByReferenceBoolean classSupported , SootClass sc , String subsig ) {
67+ if (classSupported .value )
68+ return ;
69+
70+ if (sc .getMethodUnsafe (subsig ) == null )
71+ return ;
72+
73+ ClassMethodSummaries cms = flows .getClassFlows (sc .getName ());
74+ classSupported .value |= cms != null && cms .isExclusiveForClass ();
75+ }
76+
6477 /**
6578 * Checks whether we have summaries for the given method signature in the given
6679 * class
@@ -70,47 +83,33 @@ public SummaryResponse load(SummaryQuery query) throws Exception {
7083 * @param clazz The class for which to look for summaries
7184 * @return True if summaries were found, false otherwise
7285 */
73- private boolean getSummaries (final String methodSig , final ClassSummaries summaries , SootClass clazz ) {
86+ private boolean getSummaries (final String methodSig , final ClassSummaries summaries , SootClass clazz ,
87+ ByReferenceBoolean classSupported ) {
7488 // Do we have direct support for the target class?
7589 if (summaries .merge (flows .getMethodFlows (clazz , methodSig )))
7690 return true ;
7791
7892 // Do we support any interface this class might have?
79- if (checkInterfaces (methodSig , summaries , clazz ))
93+ if (checkInterfaces (methodSig , summaries , clazz , classSupported ))
8094 return true ;
8195
96+ updateClassExclusive (classSupported , clazz , methodSig );
97+
98+ SootMethod targetMethod = clazz .getMethodUnsafe (methodSig );
8299 // If the target is abstract and we haven't found any flows,
83100 // we check for child classes
84- SootMethod targetMethod = clazz .getMethodUnsafe (methodSig );
85101 if (!clazz .isConcrete () || targetMethod == null || !targetMethod .isConcrete ()) {
86102 for (SootClass parentClass : getAllParentClasses (clazz )) {
87103 // Do we have support for the target class?
88104 if (summaries .merge (flows .getMethodFlows (parentClass , methodSig )))
89105 return true ;
90106
91107 // Do we support any interface this class might have?
92- if (checkInterfaces (methodSig , summaries , parentClass ))
108+ if (checkInterfaces (methodSig , summaries , parentClass , classSupported ))
93109 return true ;
94- }
95- }
96110
97- // In case we don't have a real hierarchy, we must reconstruct one from the
98- // summaries
99- String curClass = clazz .getName ();
100- while (curClass != null ) {
101- ClassMethodSummaries classSummaries = flows .getClassFlows (curClass );
102- if (classSummaries != null ) {
103- // Check for flows in the current class
104- if (summaries .merge (flows .getMethodFlows (curClass , methodSig )))
105- return true ;
106-
107- // Check for interfaces
108- if (checkInterfacesFromSummary (methodSig , summaries , curClass ))
109- return true ;
110-
111- curClass = classSummaries .getSuperClass ();
112- } else
113- break ;
111+ updateClassExclusive (classSupported , parentClass , methodSig );
112+ }
114113 }
115114
116115 return false ;
@@ -126,7 +125,7 @@ private boolean getSummaries(final String methodSig, final ClassSummaries summar
126125 * @return True if summaries were found, false otherwise
127126 */
128127 private boolean getSummariesHierarchy (final String methodSig , final ClassSummaries summaries ,
129- SootClass clazz ) {
128+ SootClass clazz , ByReferenceBoolean classSupported ) {
130129 // Don't try to look up the whole Java hierarchy
131130 if (clazz .getName ().equals ("java.lang.Object" ))
132131 return false ;
@@ -145,9 +144,11 @@ private boolean getSummariesHierarchy(final String methodSig, final ClassSummari
145144 found ++;
146145
147146 // Do we support any interface this class might have?
148- if (checkInterfaces (methodSig , summaries , childClass ))
147+ if (checkInterfaces (methodSig , summaries , childClass , classSupported ))
149148 found ++;
150149
150+ updateClassExclusive (classSupported , childClass , methodSig );
151+
151152 // If we have too many summaries that could be applicable, we abort here to
152153 // avoid false positives
153154 if (found > MAX_HIERARCHY_DEPTH )
@@ -167,7 +168,8 @@ private boolean getSummariesHierarchy(final String methodSig, final ClassSummari
167168 * @param clazz The interface for which to look for summaries
168169 * @return True if summaries were found, false otherwise
169170 */
170- private boolean checkInterfaces (String methodSig , ClassSummaries summaries , SootClass clazz ) {
171+ private boolean checkInterfaces (String methodSig , ClassSummaries summaries , SootClass clazz ,
172+ ByReferenceBoolean classSupported ) {
171173 for (SootClass intf : clazz .getInterfaces ()) {
172174 // Directly check the interface
173175 if (summaries .merge (flows .getMethodFlows (intf , methodSig )))
@@ -177,42 +179,13 @@ private boolean checkInterfaces(String methodSig, ClassSummaries summaries, Soot
177179 // Do we have support for the interface?
178180 if (summaries .merge (flows .getMethodFlows (parent , methodSig )))
179181 return true ;
180- }
181- }
182182
183- // We might not have hierarchy information in the scene, so let's check the
184- // summary itself
185- return checkInterfacesFromSummary (methodSig , summaries , clazz .getName ());
186- }
187-
188- /**
189- * Checks for summaries on the interfaces implemented by the given class. This
190- * method relies on the hierarchy data from the summary XML files, rather than
191- * the Soot scene
192- *
193- * @param methodSig The subsignature of the method for which to get summaries
194- * @param summaries The summary object to which to add the discovered summaries
195- * @param className The interface for which to look for summaries
196- * @return True if summaries were found, false otherwise
197- */
198- protected boolean checkInterfacesFromSummary (String methodSig , ClassSummaries summaries ,
199- String className ) {
200- List <String > interfaces = new ArrayList <>();
201- interfaces .add (className );
202- while (!interfaces .isEmpty ()) {
203- final String intfName = interfaces .remove (0 );
204- ClassMethodSummaries classSummaries = flows .getClassFlows (intfName );
205- if (classSummaries != null && classSummaries .hasInterfaces ()) {
206- for (String intf : classSummaries .getInterfaces ()) {
207- // Do we have a summary on the current interface?
208- if (summaries .merge (flows .getMethodFlows (intf , methodSig )))
209- return true ;
210-
211- // Recursively check for more interfaces
212- interfaces .add (intf );
213- }
183+ updateClassExclusive (classSupported , parent , methodSig );
214184 }
215185 }
186+
187+ // We inject the hierarchy from summaries before the data flow analysis, thus the
188+ // soot hierarchy already contains the manual information provided in the xmls.
216189 return false ;
217190 }
218191
@@ -246,7 +219,6 @@ private Set<SootClass> getAllChildClasses(SootClass sc) {
246219 Set <SootClass > doneSet = new HashSet <SootClass >();
247220 Set <SootClass > classes = new HashSet <>();
248221
249- final Scene scene = Scene .v ();
250222 while (!workList .isEmpty ()) {
251223 SootClass curClass = workList .remove (0 );
252224 if (!doneSet .add (curClass ))
@@ -255,36 +227,13 @@ private Set<SootClass> getAllChildClasses(SootClass sc) {
255227 if (curClass .isInterface ()) {
256228 List <SootClass > hierarchyImplementers = hierarchy .getImplementersOf (curClass );
257229 workList .addAll (hierarchyImplementers );
258- if (curClass .isPhantom () && hierarchyImplementers .isEmpty ()) {
259- // Query the hierarchy data in the summaries
260- flows .getImplementersOfInterface (curClass .getName ()).stream ().map (c -> scene .getSootClassUnsafe (c ))
261- .filter (c -> c != null ).forEach (c -> {
262- workList .add (c );
263- });
264- }
265230
266231 List <SootClass > subinterfaces = hierarchy .getSubinterfacesOf (curClass );
267232 workList .addAll (subinterfaces );
268- if (curClass .isPhantom () && subinterfaces .isEmpty ()) {
269- // Query the hierarchy data in the summaries
270- flows .getSubInterfacesOf (curClass .getName ()).stream ().map (c -> scene .getSootClassUnsafe (c ))
271- .filter (c -> c != null ).forEach (c -> {
272- workList .add (c );
273- });
274- }
275233 } else {
276234 List <SootClass > hierarchyClasses = hierarchy .getSubclassesOf (curClass );
277235 workList .addAll (hierarchyClasses );
278236 classes .add (curClass );
279-
280- if (curClass .isPhantom () && hierarchyClasses .isEmpty ()) {
281- // Query the hierarchy data in the summaries
282- flows .getSubclassesOf (curClass .getName ()).stream ().map (c -> scene .getSootClassUnsafe (c ))
283- .filter (c -> c != null ).forEach (c -> {
284- workList .add (c );
285- classes .add (c );
286- });
287- }
288237 }
289238 }
290239
@@ -305,7 +254,6 @@ private Set<SootClass> getAllParentClasses(SootClass sc) {
305254 Set <SootClass > doneSet = new HashSet <SootClass >();
306255 Set <SootClass > classes = new HashSet <>();
307256
308- final Scene scene = Scene .v ();
309257 while (!workList .isEmpty ()) {
310258 SootClass curClass = workList .remove (0 );
311259 if (!doneSet .add (curClass ))
@@ -314,27 +262,10 @@ private Set<SootClass> getAllParentClasses(SootClass sc) {
314262 if (curClass .isInterface ()) {
315263 List <SootClass > hierarchyClasses = hierarchy .getSuperinterfacesOf (curClass );
316264 workList .addAll (hierarchyClasses );
317-
318- if (curClass .isPhantom () && hierarchyClasses .isEmpty ()) {
319- // Query the hierarchy data in the summaries
320- flows .getSuperinterfacesOf (curClass .getName ()).stream ().map (c -> scene .getSootClassUnsafe (c ))
321- .filter (c -> c != null ).forEach (c -> {
322- workList .add (c );
323- });
324- }
325265 } else {
326266 List <SootClass > hierarchyClasses = hierarchy .getSuperclassesOf (curClass );
327267 workList .addAll (hierarchyClasses );
328268 classes .add (curClass );
329-
330- if (curClass .isPhantom () && hierarchyClasses .isEmpty ()) {
331- // Query the hierarchy data in the summaries
332- flows .getSuperclassesOf (curClass .getName ()).stream ().map (c -> scene .getSootClassUnsafe (c ))
333- .filter (c -> c != null ).forEach (c -> {
334- workList .add (c );
335- classes .add (c );
336- });
337- }
338269 }
339270 }
340271
0 commit comments