2424import java .util .List ;
2525import java .util .Map ;
2626import java .util .Set ;
27+ import java .util .concurrent .ExecutionException ;
2728
2829import org .slf4j .Logger ;
2930import org .slf4j .LoggerFactory ;
3031
32+ import com .google .common .cache .CacheBuilder ;
33+ import com .google .common .cache .CacheLoader ;
34+ import com .google .common .cache .LoadingCache ;
35+
36+ import heros .solver .Pair ;
3137import soot .AnySubType ;
3238import soot .Body ;
3339import soot .FastHierarchy ;
3642import soot .RefType ;
3743import soot .Scene ;
3844import soot .SootClass ;
45+ import soot .SootField ;
3946import soot .SootMethod ;
4047import soot .SootMethodRef ;
4148import soot .Type ;
4249import soot .Unit ;
4350import soot .Value ;
51+ import soot .jimple .ArrayRef ;
52+ import soot .jimple .AssignStmt ;
53+ import soot .jimple .CastExpr ;
4454import soot .jimple .ClassConstant ;
55+ import soot .jimple .FieldRef ;
4556import soot .jimple .IdentityStmt ;
4657import soot .jimple .InstanceInvokeExpr ;
4758import soot .jimple .InvokeExpr ;
5970import soot .jimple .infoflow .values .IValueProvider ;
6071import soot .jimple .infoflow .values .SimpleConstantValueProvider ;
6172import soot .jimple .toolkits .callgraph .Edge ;
73+ import soot .toolkits .graph .ExceptionalUnitGraph ;
74+ import soot .toolkits .graph .ExceptionalUnitGraphFactory ;
75+ import soot .toolkits .scalar .SimpleLocalDefs ;
6276import soot .util .HashMultiMap ;
6377import soot .util .MultiMap ;
6478
@@ -94,10 +108,16 @@ public abstract class AbstractCallbackAnalyzer {
94108
95109 protected final SootClass scSupportViewPager = Scene .v ().getSootClassUnsafe ("android.support.v4.view.ViewPager" );
96110 protected final SootClass scAndroidXViewPager = Scene .v ().getSootClassUnsafe ("androidx.viewpager.widget.ViewPager" );
111+
97112 protected final SootClass scFragmentStatePagerAdapter = Scene .v ()
98113 .getSootClassUnsafe ("android.support.v4.app.FragmentStatePagerAdapter" );
114+ protected final SootClass scFragmentPagerAdapter = Scene .v ()
115+ .getSootClassUnsafe ("android.support.v4.app.FragmentPagerAdapter" );
116+
99117 protected final SootClass scAndroidXFragmentStatePagerAdapter = Scene .v ()
100118 .getSootClassUnsafe ("androidx.fragment.app.FragmentStatePagerAdapter" );
119+ protected final SootClass scAndroidXFragmentPagerAdapter = Scene .v ()
120+ .getSootClassUnsafe ("androidx.fragment.app.FragmentPagerAdapter" );
101121
102122 protected final InfoflowAndroidConfiguration config ;
103123 protected final Set <SootClass > entryPointClasses ;
@@ -115,6 +135,69 @@ public abstract class AbstractCallbackAnalyzer {
115135
116136 protected IValueProvider valueProvider = new SimpleConstantValueProvider ();
117137
138+ protected LoadingCache <SootField , List <Type >> arrayToContentTypes = CacheBuilder .newBuilder ()
139+ .build (new CacheLoader <SootField , List <Type >>() {
140+
141+ @ Override
142+ public List <Type > load (SootField field ) throws Exception {
143+ // Find all assignments to this field
144+ List <Type > typeList = new ArrayList <>();
145+ field .getDeclaringClass ().getMethods ().stream ().filter (m -> m .isConcrete ())
146+ .map (m -> m .retrieveActiveBody ()).forEach (b -> {
147+ // Find all locals that reference the field
148+ Set <Local > arrayLocals = new HashSet <>();
149+ for (Unit u : b .getUnits ()) {
150+ if (u instanceof AssignStmt ) {
151+ AssignStmt assignStmt = (AssignStmt ) u ;
152+ Value rop = assignStmt .getRightOp ();
153+ Value lop = assignStmt .getLeftOp ();
154+ if (rop instanceof FieldRef && ((FieldRef ) rop ).getField () == field ) {
155+ arrayLocals .add ((Local ) lop );
156+ } else if (lop instanceof FieldRef && ((FieldRef ) lop ).getField () == field ) {
157+ arrayLocals .add ((Local ) rop );
158+ }
159+ }
160+ }
161+
162+ // Find casts
163+ for (Unit u : b .getUnits ()) {
164+ if (u instanceof AssignStmt ) {
165+ AssignStmt assignStmt = (AssignStmt ) u ;
166+ Value rop = assignStmt .getRightOp ();
167+ Value lop = assignStmt .getLeftOp ();
168+
169+ if (rop instanceof CastExpr ) {
170+ CastExpr ce = (CastExpr ) rop ;
171+ if (arrayLocals .contains (ce .getOp ()))
172+ arrayLocals .add ((Local ) lop );
173+ else if (arrayLocals .contains (lop ))
174+ arrayLocals .add ((Local ) ce .getOp ());
175+ }
176+ }
177+ }
178+
179+ // Find the assignments to the array locals
180+ for (Unit u : b .getUnits ()) {
181+ if (u instanceof AssignStmt ) {
182+ AssignStmt assignStmt = (AssignStmt ) u ;
183+ Value rop = assignStmt .getRightOp ();
184+ Value lop = assignStmt .getLeftOp ();
185+ if (lop instanceof ArrayRef ) {
186+ ArrayRef arrayRef = (ArrayRef ) lop ;
187+ if (arrayLocals .contains (arrayRef .getBase ())) {
188+ Type t = rop .getType ();
189+ if (t instanceof RefType )
190+ typeList .add (rop .getType ());
191+ }
192+ }
193+ }
194+ }
195+ });
196+ return typeList ;
197+ }
198+
199+ });
200+
118201 public AbstractCallbackAnalyzer (InfoflowAndroidConfiguration config , Set <SootClass > entryPointClasses )
119202 throws IOException {
120203 this (config , entryPointClasses , "AndroidCallbacks.txt" );
@@ -488,15 +571,23 @@ else if (methodName.equals("inflate") && stmt.getInvokeExpr().getArgCount() > 1)
488571 * @author Julius Naeumann
489572 */
490573 protected void analyzeMethodForViewPagers (SootClass clazz , SootMethod method ) {
491- if (scSupportViewPager == null || scFragmentStatePagerAdapter == null )
492- if (scAndroidXViewPager == null || scAndroidXFragmentStatePagerAdapter == null )
493- return ;
574+ // We need at least one fragment base class
575+ if (scSupportViewPager == null && scAndroidXViewPager == null )
576+ return ;
577+ // We need at least one class with a method to register a fragment
578+ if (scFragmentStatePagerAdapter == null && scAndroidXFragmentStatePagerAdapter == null
579+ && scFragmentPagerAdapter == null && scAndroidXFragmentPagerAdapter == null )
580+ return ;
494581
495582 if (!method .isConcrete ())
496583 return ;
497584
498585 Body body = method .retrieveActiveBody ();
499586
587+ if (method .getDeclaringClass ().getName ().equals ("org.liberty.android.fantastischmemo.ui.AnyMemo" )
588+ && method .getName ().equals ("initDrawer" ))
589+ System .out .println ("x" );
590+
500591 // look for invocations of ViewPager.setAdapter
501592 for (Unit u : body .getUnits ()) {
502593 Stmt stmt = (Stmt ) u ;
@@ -525,7 +616,8 @@ protected void analyzeMethodForViewPagers(SootClass clazz, SootMethod method) {
525616 RefType rt = (RefType ) pa .getType ();
526617
527618 // check whether argument is of type FragmentStatePagerAdapter
528- if (!safeIsType (pa , scFragmentStatePagerAdapter ) && !safeIsType (pa , scAndroidXFragmentStatePagerAdapter ))
619+ if (!safeIsType (pa , scFragmentStatePagerAdapter ) && !safeIsType (pa , scAndroidXFragmentStatePagerAdapter )
620+ && !safeIsType (pa , scFragmentPagerAdapter ) && !safeIsType (pa , scAndroidXFragmentPagerAdapter ))
529621 continue ;
530622
531623 // now analyze getItem() to find possible Fragments
@@ -546,7 +638,59 @@ protected void analyzeMethodForViewPagers(SootClass clazz, SootMethod method) {
546638 Value rv = rs .getOp ();
547639 Type type = rv .getType ();
548640 if (type instanceof RefType ) {
549- checkAndAddFragment (method .getDeclaringClass (), ((RefType ) type ).getSootClass ());
641+ SootClass rtClass = ((RefType ) type ).getSootClass ();
642+ if (rv instanceof Local && (rtClass .getName ().startsWith ("android." )
643+ || rtClass .getName ().startsWith ("androidx." )))
644+ analyzeFragmentCandidates (rs , getItem , (Local ) rv );
645+ else
646+ checkAndAddFragment (method .getDeclaringClass (), rtClass );
647+ }
648+ }
649+ }
650+ }
651+ }
652+
653+ /**
654+ * Attempts to find fragments that are not returned immediately, but that
655+ * require a more complex backward analysis. This analysis is best-effort, we do
656+ * not attempt to solve every possible case.
657+ *
658+ * @param s The statement at which the fragment is returned
659+ * @param m The method in which the fragment is returned
660+ * @param l The local that contains the fragment
661+ */
662+ private void analyzeFragmentCandidates (Stmt s , SootMethod m , Local l ) {
663+ ExceptionalUnitGraph g = ExceptionalUnitGraphFactory .createExceptionalUnitGraph (m .getActiveBody ());
664+ SimpleLocalDefs lds = new SimpleLocalDefs (g );
665+
666+ List <Pair <Local , Stmt >> toSearch = new ArrayList <>();
667+ Set <Pair <Local , Stmt >> doneSet = new HashSet <>();
668+ toSearch .add (new Pair <>(l , s ));
669+
670+ while (!toSearch .isEmpty ()) {
671+ Pair <Local , Stmt > pair = toSearch .remove (0 );
672+ if (doneSet .add (pair )) {
673+ List <Unit > defs = lds .getDefsOfAt (pair .getO1 (), pair .getO2 ());
674+ for (Unit def : defs ) {
675+ if (def instanceof AssignStmt ) {
676+ AssignStmt assignStmt = (AssignStmt ) def ;
677+ Value rop = assignStmt .getRightOp ();
678+ if (rop instanceof ArrayRef ) {
679+ ArrayRef arrayRef = (ArrayRef ) rop ;
680+
681+ // Look for all assignments to the array
682+ toSearch .add (new Pair <>((Local ) arrayRef .getBase (), assignStmt ));
683+ } else if (rop instanceof FieldRef ) {
684+ FieldRef fieldRef = (FieldRef ) rop ;
685+ try {
686+ List <Type > typeList = arrayToContentTypes .get (fieldRef .getField ());
687+ typeList .stream ().map (t -> ((RefType ) t ).getSootClass ())
688+ .forEach (c -> checkAndAddFragment (m .getDeclaringClass (), c ));
689+ } catch (ExecutionException e ) {
690+ logger .error (String .format ("Could not load potential types for field %s" ,
691+ fieldRef .getField ().getSignature ()), e );
692+ }
693+ }
550694 }
551695 }
552696 }
0 commit comments