diff --git a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaSSAPropagationCallGraphBuilder.java b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaSSAPropagationCallGraphBuilder.java index f868e3a12..7230b4539 100644 --- a/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaSSAPropagationCallGraphBuilder.java +++ b/com.ibm.wala.cast.java/src/com/ibm/wala/cast/java/ipa/callgraph/AstJavaSSAPropagationCallGraphBuilder.java @@ -256,7 +256,7 @@ public class AstJavaSSAPropagationCallGraphBuilder extends AstSSAPropagationCall System.err.println(("class is " + klass + ", enclosing is " + enclosingClass + ", method is " + node.getMethod())); - if (node.getMethod().isSynthetic()) { + if (node.getMethod().isWalaSynthetic()) { return; } diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstClass.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstClass.java index 5f5111219..1e7e2ed9d 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstClass.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstClass.java @@ -85,6 +85,11 @@ abstract public class AstClass implements IClass, ClassConstants { return false; } + @Override + public boolean isSynthetic() { + return false; + } + @Override public int getModifiers() { return modifiers; diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstFunctionClass.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstFunctionClass.java index b148e99c3..3e0115b58 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstFunctionClass.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstFunctionClass.java @@ -91,6 +91,11 @@ abstract public class AstFunctionClass implements IClass, ClassConstants { return false; } + @Override + public boolean isSynthetic() { + return false; + } + @Override public int getModifiers() { return ACC_PUBLIC; diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstMethod.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstMethod.java index 3241a2fe5..441da953a 100644 --- a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstMethod.java +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstMethod.java @@ -267,6 +267,11 @@ public abstract class AstMethod implements IMethod { return qualifiers.contains(CAstQualifier.NATIVE); } + @Override + public boolean isWalaSynthetic() { + return false; + } + @Override public boolean isSynthetic() { return false; diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryBypassInterpreter.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryBypassInterpreter.java index dccf8a0ff..e6c57a5af 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryBypassInterpreter.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryBypassInterpreter.java @@ -141,7 +141,7 @@ public class FactoryBypassInterpreter extends AbstractReflectionInterpreter { if (node == null) { throw new IllegalArgumentException("node is null"); } - if (node.getMethod().isSynthetic()) { + if (node.getMethod().isWalaSynthetic()) { SyntheticMethod s = (SyntheticMethod) node.getMethod(); if (s.isFactoryMethod()) { return getTypesForContext(node.getContext()) != null; diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryContextSelector.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryContextSelector.java index a02807a76..ba43e6e05 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryContextSelector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/reflection/FactoryContextSelector.java @@ -38,7 +38,7 @@ class FactoryContextSelector implements ContextSelector { if (callee == null) { throw new IllegalArgumentException("callee is null"); } - if (callee.isSynthetic()) { + if (callee.isWalaSynthetic()) { SyntheticMethod s = (SyntheticMethod) callee; if (s.isFactoryMethod()) { return new CallStringContext(new CallString(site, caller.getMethod())); diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ArrayClass.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ArrayClass.java index fcb3f18ea..ce1cec267 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ArrayClass.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ArrayClass.java @@ -371,6 +371,11 @@ public class ArrayClass implements IClass, Constants { return false; } + @Override + public boolean isSynthetic() { + return false; + } + @Override public Reader getSource() { return null; diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/CodeScanner.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/CodeScanner.java index 27e7c91fe..feac607b3 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/CodeScanner.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/CodeScanner.java @@ -46,7 +46,7 @@ public class CodeScanner { if (m == null) { throw new IllegalArgumentException("m is null"); } - if (m.isSynthetic()) { + if (m.isWalaSynthetic()) { SyntheticMethod sm = (SyntheticMethod) m; return getCallSites(sm.getStatements()); } else { @@ -62,7 +62,7 @@ public class CodeScanner { if (m == null) { throw new IllegalArgumentException("m is null"); } - if (m.isSynthetic()) { + if (m.isWalaSynthetic()) { SyntheticMethod sm = (SyntheticMethod) m; return getFieldsRead(sm.getStatements()); } else { @@ -78,7 +78,7 @@ public class CodeScanner { if (m == null) { throw new IllegalArgumentException("m is null"); } - if (m.isSynthetic()) { + if (m.isWalaSynthetic()) { SyntheticMethod sm = (SyntheticMethod) m; return getFieldsWritten(sm.getStatements()); } else { @@ -95,7 +95,7 @@ public class CodeScanner { if (m == null) { throw new IllegalArgumentException("m is null"); } - if (m.isSynthetic()) { + if (m.isWalaSynthetic()) { SyntheticMethod sm = (SyntheticMethod) m; return getArraysWritten(sm.getStatements()); } else { @@ -111,7 +111,7 @@ public class CodeScanner { if (m == null) { throw new IllegalArgumentException("m is null"); } - if (m.isSynthetic()) { + if (m.isWalaSynthetic()) { SyntheticMethod sm = (SyntheticMethod) m; return getNewSites(sm.getStatements()); } else { @@ -123,7 +123,7 @@ public class CodeScanner { if (m == null) { throw new IllegalArgumentException("m is null"); } - if (m.isSynthetic()) { + if (m.isWalaSynthetic()) { SyntheticMethod sm = (SyntheticMethod) m; return hasObjectArrayLoad(sm.getStatements()); } else { @@ -135,7 +135,7 @@ public class CodeScanner { if (m == null) { throw new IllegalArgumentException("m is null"); } - if (m.isSynthetic()) { + if (m.isWalaSynthetic()) { SyntheticMethod sm = (SyntheticMethod) m; return hasObjectArrayStore(sm.getStatements()); } else { @@ -147,7 +147,7 @@ public class CodeScanner { if (m == null) { throw new IllegalArgumentException("m is null"); } - if (m.isSynthetic()) { + if (m.isWalaSynthetic()) { SyntheticMethod sm = (SyntheticMethod) m; return getCaughtExceptions(sm.getStatements()); } else { @@ -166,7 +166,7 @@ public class CodeScanner { if (m == null) { throw new IllegalArgumentException("m is null"); } - if (m.isSynthetic()) { + if (m.isWalaSynthetic()) { SyntheticMethod sm = (SyntheticMethod) m; return iterateCastTypes(sm.getStatements()); } else { diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/IClass.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/IClass.java index a1730088e..cf22cb08e 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/IClass.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/IClass.java @@ -54,6 +54,11 @@ public interface IClass extends IClassHierarchyDweller { */ boolean isPrivate(); + /** + * @return true iff this class is synthetic, i.e., compiler-generated + */ + boolean isSynthetic(); + /** * Return the integer that encodes the class's modifiers, as defined by the JVM specification * diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/IMethod.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/IMethod.java index 26c07dd57..785600f3f 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/IMethod.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/IMethod.java @@ -43,7 +43,14 @@ public interface IMethod extends IMember, ContextItem { boolean isNative(); /** - * Did someone synthesize this method? (As opposed to reading it from a class file) + * Is the implementation of this method a model generated by WALA? + * For compiler-generated synthetic methods, refer to {@link #isSynthetic()} + */ + boolean isWalaSynthetic(); + + /** + * Is this method synthetic, i.e., compiler-generated (this refers to the + * synthetic flag in java/dex bytecode) */ boolean isSynthetic(); diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/JVMClass.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/JVMClass.java index 899584c89..c20c116dc 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/JVMClass.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/JVMClass.java @@ -65,6 +65,15 @@ public abstract class JVMClass extends BytecodeClass return result; } + /* + * @see com.ibm.wala.classLoader.IClass#isSynthetic() + */ + @Override + public boolean isSynthetic() { + boolean result = ((modifiers & Constants.ACC_SYNTHETIC) != 0); + return result; + } + /** * @see com.ibm.wala.classLoader.IClass#getClassInitializer() */ diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeBTMethod.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeBTMethod.java index cfe05a086..8ed7e8d9a 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeBTMethod.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/ShrikeBTMethod.java @@ -441,7 +441,10 @@ public abstract class ShrikeBTMethod implements IMethod, BytecodeConstants { } @Override - public boolean isSynthetic() { + public boolean isSynthetic() { return ((getModifiers() & Constants.ACC_SYNTHETIC) != 0); } + + @Override + public boolean isWalaSynthetic() { return false; } diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/SyntheticClass.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/SyntheticClass.java index cdf8741f0..295610002 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/SyntheticClass.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/SyntheticClass.java @@ -95,6 +95,16 @@ public abstract class SyntheticClass implements IClass { return false; } + /* + * These classes are generated by WALA, not by any + * compiler, therefore it always returns false + * @see com.ibm.wala.classLoader.IClass#isSynthetic() + */ + @Override + public boolean isSynthetic() { + return false; + } + /* * @see com.ibm.wala.classLoader.IClass#getReference() */ @@ -123,7 +133,7 @@ public abstract class SyntheticClass implements IClass { public boolean isArrayClass() { return false; } - + @Override public IClassHierarchy getClassHierarchy() { return cha; diff --git a/com.ibm.wala.core/src/com/ibm/wala/classLoader/SyntheticMethod.java b/com.ibm.wala.core/src/com/ibm/wala/classLoader/SyntheticMethod.java index 4d0915340..f4ddf33f8 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/classLoader/SyntheticMethod.java +++ b/com.ibm.wala.core/src/com/ibm/wala/classLoader/SyntheticMethod.java @@ -153,12 +153,20 @@ public class SyntheticMethod implements IMethod { return false; } + /** + * @see com.ibm.wala.classLoader.IMethod#isWalaSynthetic() + */ + @Override + public boolean isWalaSynthetic() { + return true; + } + /** * @see com.ibm.wala.classLoader.IMethod#isSynthetic() */ @Override public boolean isSynthetic() { - return true; + return false; } /** diff --git a/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/SimpleMemoryAccessMap.java b/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/SimpleMemoryAccessMap.java index 2198d3630..853989e14 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/SimpleMemoryAccessMap.java +++ b/com.ibm.wala.core/src/com/ibm/wala/demandpa/util/SimpleMemoryAccessMap.java @@ -102,7 +102,7 @@ public class SimpleMemoryAccessMap implements MemoryAccessMap { private void populate(CGNode n) { // we analyze bytecodes to avoid the cost of IR construction, except // for synthetic methods, where we must use the synthetic IR - if (ALWAYS_BUILD_IR || n.getMethod().isSynthetic()) { + if (ALWAYS_BUILD_IR || n.getMethod().isWalaSynthetic()) { if (DEBUG) { System.err.println("synthetic method"); } diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/BasicCallGraph.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/BasicCallGraph.java index 87136655b..b098de037 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/BasicCallGraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/BasicCallGraph.java @@ -184,7 +184,7 @@ public abstract class BasicCallGraph extends AbstractNumberedGraph im protected NodeImpl(IMethod method, Context C) { this.method = method; this.context = C; - if (method != null && !method.isSynthetic() && method.isAbstract()) { + if (method != null && !method.isWalaSynthetic() && method.isAbstract()) { assert !method.isAbstract() : "Abstract method " + method; } assert C != null; diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ExplicitCallGraph.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ExplicitCallGraph.java index 3b68290a4..1b8d95e6f 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ExplicitCallGraph.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/impl/ExplicitCallGraph.java @@ -297,7 +297,7 @@ public class ExplicitCallGraph extends BasicCallGraph imp @Override public IR getIR() { - if (getMethod().isSynthetic()) { + if (getMethod().isWalaSynthetic()) { // disable local cache in this case, as context interpreters // do weird things like mutate IRs return getCallGraph().getInterpreter(this).getIR(this); @@ -312,7 +312,7 @@ public class ExplicitCallGraph extends BasicCallGraph imp @Override public DefUse getDU() { - if (getMethod().isSynthetic()) { + if (getMethod().isWalaSynthetic()) { // disable local cache in this case, as context interpreters // do weird things like mutate IRs return getCallGraph().getInterpreter(this).getDU(this); diff --git a/com.ibm.wala.core/src/com/ibm/wala/ssa/DefaultIRFactory.java b/com.ibm.wala.core/src/com/ibm/wala/ssa/DefaultIRFactory.java index b00fc9e19..c36929e73 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ssa/DefaultIRFactory.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ssa/DefaultIRFactory.java @@ -40,7 +40,7 @@ public class DefaultIRFactory implements IRFactory { if (method == null) { throw new IllegalArgumentException("method cannot be null"); } - if (method.isSynthetic()) { + if (method.isWalaSynthetic()) { return syntheticFactory.makeCFG((SyntheticMethod) method); } else if (method instanceof IBytecodeMethod) { @SuppressWarnings("unchecked") @@ -61,7 +61,7 @@ public class DefaultIRFactory implements IRFactory { if (method == null) { throw new IllegalArgumentException("method cannot be null"); } - if (method.isSynthetic()) { + if (method.isWalaSynthetic()) { return syntheticFactory.makeIR((SyntheticMethod) method, c, options); } else if (method instanceof IBytecodeMethod) { @SuppressWarnings("unchecked") @@ -81,7 +81,7 @@ public class DefaultIRFactory implements IRFactory { if (method == null) { throw new IllegalArgumentException("null method"); } - if (method.isSynthetic()) { + if (method.isWalaSynthetic()) { return syntheticFactory.contextIsIrrelevant((SyntheticMethod) method); } else if (method instanceof ShrikeCTMethod) { // we know ShrikeFactory contextIsIrrelevant diff --git a/com.ibm.wala.dalvik.test/META-INF/MANIFEST.MF b/com.ibm.wala.dalvik.test/META-INF/MANIFEST.MF index a5c0cbf37..f4148ee09 100644 --- a/com.ibm.wala.dalvik.test/META-INF/MANIFEST.MF +++ b/com.ibm.wala.dalvik.test/META-INF/MANIFEST.MF @@ -21,4 +21,5 @@ Export-Package: com.ibm.wala.dalvik.drivers, com.ibm.wala.dalvik.test.callGraph, com.ibm.wala.dalvik.test.callGraph.droidbench, com.ibm.wala.dalvik.test.ir, + com.ibm.wala.dalvik.test.cha, com.ibm.wala.dalvik.test.util diff --git a/com.ibm.wala.dalvik.test/data/multidex-test.apk b/com.ibm.wala.dalvik.test/data/multidex-test.apk new file mode 100644 index 000000000..80d456e93 Binary files /dev/null and b/com.ibm.wala.dalvik.test/data/multidex-test.apk differ diff --git a/com.ibm.wala.dalvik.test/source/com/ibm/wala/dalvik/test/callGraph/DroidBenchCGTest.java b/com.ibm.wala.dalvik.test/source/com/ibm/wala/dalvik/test/callGraph/DroidBenchCGTest.java index 3f76514c6..88aa13ee0 100644 --- a/com.ibm.wala.dalvik.test/source/com/ibm/wala/dalvik/test/callGraph/DroidBenchCGTest.java +++ b/com.ibm.wala.dalvik.test/source/com/ibm/wala/dalvik/test/callGraph/DroidBenchCGTest.java @@ -144,15 +144,20 @@ public abstract class DroidBenchCGTest extends DalvikCallGraphTestBase { } public static Collection generateData(final URI[] androidLibs, final File androidJavaJar, final String filter) { - String f = walaProperties.getProperty("droidbench.root"); - if (f == null || !new File(f).exists()) { - f = "/tmp/DroidBench"; - } - - System.err.println("Use " + f + " as droid bench root"); - assert new File(f).exists() : "Use " + f + " as droid bench root"; - assert new File(f + "/apk/").exists() : "Use " + f + " as droid bench root"; - return generateData(f, androidLibs, androidJavaJar, filter); + + return generateData(getDroidBenchRoot(), androidLibs, androidJavaJar, filter); + } + + public static String getDroidBenchRoot(){ + String f = walaProperties.getProperty("droidbench.root"); + if (f == null || !new File(f).exists()) { + f = "/tmp/DroidBench"; + } + + System.err.println("Use " + f + " as droid bench root"); + assert new File(f).exists() : "Use " + f + " as droid bench root"; + assert new File(f + "/apk/").exists() : "Use " + f + " as droid bench root"; + return f; } public static Collection generateData(String droidBenchRoot, final URI[] androidLibs, final File androidJavaJar, final String filter) { diff --git a/com.ibm.wala.dalvik.test/source/com/ibm/wala/dalvik/test/callGraph/JVMLDalvikComparisonTest.java b/com.ibm.wala.dalvik.test/source/com/ibm/wala/dalvik/test/callGraph/JVMLDalvikComparisonTest.java index 098a71eff..c52445698 100644 --- a/com.ibm.wala.dalvik.test/source/com/ibm/wala/dalvik/test/callGraph/JVMLDalvikComparisonTest.java +++ b/com.ibm.wala.dalvik.test/source/com/ibm/wala/dalvik/test/callGraph/JVMLDalvikComparisonTest.java @@ -63,9 +63,9 @@ public class JVMLDalvikComparisonTest extends DalvikCallGraphTestBase { private static Set> edgeDiff(CallGraph from, CallGraph to, boolean userOnly) { Set> result = HashSetFactory.make(); for(CGNode f : from) { - if (! f.getMethod().isSynthetic()) { + if (! f.getMethod().isWalaSynthetic()) { outer: for(CGNode t : from) { - if (!t.getMethod().isSynthetic() && + if (!t.getMethod().isWalaSynthetic() && from.hasEdge(f, t) && (!userOnly || !t.getMethod().getDeclaringClass().getClassLoader().getReference().equals(ClassLoaderReference.Primordial))) diff --git a/com.ibm.wala.dalvik.test/source/com/ibm/wala/dalvik/test/cha/MultiDexScopeTest.java b/com.ibm.wala.dalvik.test/source/com/ibm/wala/dalvik/test/cha/MultiDexScopeTest.java new file mode 100644 index 000000000..afcbdf006 --- /dev/null +++ b/com.ibm.wala.dalvik.test/source/com/ibm/wala/dalvik/test/cha/MultiDexScopeTest.java @@ -0,0 +1,99 @@ +package com.ibm.wala.dalvik.test.cha; + +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.dalvik.classLoader.DexFileModule; +import com.ibm.wala.dalvik.test.callGraph.DroidBenchCGTest; +import com.ibm.wala.dalvik.test.util.Util; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ipa.cha.ClassHierarchyFactory; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.util.config.AnalysisScopeReader; +import org.jf.dexlib2.DexFileFactory; +import org.jf.dexlib2.Opcodes; +import org.jf.dexlib2.dexbacked.DexBackedDexFile; +import org.jf.dexlib2.iface.MultiDexContainer; +import org.junit.Assert; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; + +public class MultiDexScopeTest { + + private static void addAPKtoScope(ClassLoaderReference loader, AnalysisScope scope, String fileName){ + File apkFile = new File(fileName); + MultiDexContainer multiDex = null; + try { + multiDex = DexFileFactory.loadDexContainer(apkFile, Opcodes.forApi(24)); + } catch (IOException e) { + throw new RuntimeException(e); + } + + try{ + for (String dexEntry : multiDex.getDexEntryNames()) { + System.out.println("Adding dex file: " +dexEntry + " of file:" + fileName); + scope.addToScope(loader, new DexFileModule(apkFile, dexEntry,24)); + } + }catch (IOException e){ + throw new RuntimeException(e); + } + } + + private static AnalysisScope setUpTestScope(String apkName, String exclusions, ClassLoader loader) throws IOException { + AnalysisScope scope; + scope = AnalysisScopeReader.readJavaScope("primordial.txt", new File(exclusions), loader); + scope.setLoaderImpl(ClassLoaderReference.Application, + "com.ibm.wala.dalvik.classLoader.WDexClassLoaderImpl"); + + addAPKtoScope(ClassLoaderReference.Application, scope, apkName); + return scope; + } + + private static int getNumberOfAppClasses(ClassHierarchy cha){ + Iterator classes = cha.iterator(); + int numberOfClasses = 0; + while(classes.hasNext()){ + if(classes.next().getClassLoader().getName().toString().equals("Application")) + numberOfClasses++; + } + return numberOfClasses; + } + + @Test + public void testAPK() throws ClassHierarchyException, IOException { + AnalysisScope scope, scope2; + ClassHierarchy cha, cha2; + String testAPK = DroidBenchCGTest.getDroidBenchRoot() + "/apk/Aliasing/Merge1.apk"; + + scope = setUpTestScope(testAPK,"", MultiDexScopeTest.class.getClassLoader()); + cha = ClassHierarchyFactory.make(scope); + + scope2 = Util.makeDalvikScope(null,null, testAPK); + cha2 = ClassHierarchyFactory.make(scope2); + + Assert.assertEquals(Integer.valueOf(getNumberOfAppClasses(cha)), Integer.valueOf(getNumberOfAppClasses(cha2))); + } + + @Test + public void testMultiDex() throws ClassHierarchyException, IOException { + AnalysisScope scope, scope2; + ClassHierarchy cha, cha2; + String multidexApk = "data/multidex-test.apk"; + + scope = setUpTestScope(multidexApk,"", MultiDexScopeTest.class.getClassLoader()); + cha = ClassHierarchyFactory.make(scope); + + scope2 = Util.makeDalvikScope(null,null, multidexApk); + cha2 = ClassHierarchyFactory.make(scope2); + + Assert.assertEquals(Integer.valueOf(getNumberOfAppClasses(cha)),Integer.valueOf(5)); + Assert.assertNotEquals(Integer.valueOf(getNumberOfAppClasses(cha)), Integer.valueOf(getNumberOfAppClasses(cha2))); + + } + + + +} diff --git a/com.ibm.wala.dalvik/.settings/org.eclipse.jdt.core.prefs b/com.ibm.wala.dalvik/.settings/org.eclipse.jdt.core.prefs index 8f8e42d99..c3a52e097 100644 --- a/com.ibm.wala.dalvik/.settings/org.eclipse.jdt.core.prefs +++ b/com.ibm.wala.dalvik/.settings/org.eclipse.jdt.core.prefs @@ -79,7 +79,7 @@ org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=error org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore -org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=error +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning org.eclipse.jdt.core.compiler.problem.rawTypeReference=error org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=error org.eclipse.jdt.core.compiler.problem.redundantNullCheck=error diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/classLoader/DexFileModule.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/classLoader/DexFileModule.java index c20383b3d..0d30d861a 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/classLoader/DexFileModule.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/classLoader/DexFileModule.java @@ -120,6 +120,30 @@ public class DexFileModule implements Module { } } + /** + * @param f + * the .dex or .apk file + * @param entry + * the name of the .dex file inside the apk + * @param apiLevel + * the api level wanted + * @throws IllegalArgumentException + */ + public DexFileModule(File f, String entry, int apiLevel) throws IllegalArgumentException { + try { + this.f = f; + dexfile = DexFileFactory.loadDexEntry(f, entry,true, Opcodes.forApi(apiLevel)); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + + // create ModuleEntries from ClassDefItem + entries = new HashSet<>(); + for (ClassDef cdefitems : dexfile.getClasses()) { + entries.add(new DexModuleEntry(cdefitems, this)); + } + } + /** * @return The DexFile associated to this module. */ diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/classLoader/DexIClass.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/classLoader/DexIClass.java index 5bcc32a2c..7ab8ea3b5 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/classLoader/DexIClass.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/classLoader/DexIClass.java @@ -51,6 +51,7 @@ import static org.jf.dexlib2.AccessFlags.ABSTRACT; import static org.jf.dexlib2.AccessFlags.INTERFACE; import static org.jf.dexlib2.AccessFlags.PRIVATE; import static org.jf.dexlib2.AccessFlags.PUBLIC; +import static org.jf.dexlib2.AccessFlags.SYNTHETIC; import java.util.ArrayList; import java.util.Collection; @@ -229,6 +230,13 @@ public class DexIClass extends BytecodeClass { return (modifiers & ABSTRACT.getValue()) != 0; } + /* + * @see com.ibm.wala.classLoader.IClass#isAbstract() + */ + @Override + public boolean isSynthetic() { + return (modifiers & SYNTHETIC.getValue()) != 0; + } /* * (non-Javadoc) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/classLoader/DexIMethod.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/classLoader/DexIMethod.java index fdb9d71a9..e66200563 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/classLoader/DexIMethod.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/classLoader/DexIMethod.java @@ -59,6 +59,7 @@ import static org.jf.dexlib2.AccessFlags.PROTECTED; import static org.jf.dexlib2.AccessFlags.PUBLIC; import static org.jf.dexlib2.AccessFlags.STATIC; import static org.jf.dexlib2.AccessFlags.VOLATILE; +import static org.jf.dexlib2.AccessFlags.SYNTHETIC; import java.util.ArrayList; import java.util.Collection; @@ -508,13 +509,20 @@ public class DexIMethod implements IBytecodeMethod { /* * (non-Javadoc) - * @see com.ibm.wala.classLoader.IMethod#isSynthetic() + * @see com.ibm.wala.classLoader.IMethod#isWalaSynthetic() */ @Override - public boolean isSynthetic() { + public boolean isWalaSynthetic() { return false; } + /* + * (non-Javadoc) + * @see com.ibm.wala.classLoader.IMethod#isSynthetic() + */ + @Override + public boolean isSynthetic() { return (eMethod.getAccessFlags() & SYNTHETIC.getValue()) != 0; } + /* * (non-Javadoc) * @see com.ibm.wala.classLoader.IMember#isStatic() diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidAnalysisScope.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidAnalysisScope.java index 00a35099d..94ba5c403 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidAnalysisScope.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidAnalysisScope.java @@ -33,16 +33,19 @@ public class AndroidAnalysisScope { public static AnalysisScope setUpAndroidAnalysisScope(URI classpath, String exclusions, ClassLoader loader, URI... androidLib) throws IOException { AnalysisScope scope; + File exclusionsFile = exclusions != null? new File(exclusions) : null; + if (androidLib == null || androidLib.length == 0) { - scope = AnalysisScopeReader.readJavaScope(BASIC_FILE, new File(exclusions), loader); + scope = AnalysisScopeReader.readJavaScope(BASIC_FILE, exclusionsFile, loader); } else { scope = AnalysisScope.createJavaAnalysisScope(); - File exclusionsFile = new File(exclusions); - try (final InputStream fs = exclusionsFile.exists()? new FileInputStream(exclusionsFile): FileProvider.class.getClassLoader().getResourceAsStream(exclusionsFile.getName())) { - scope.setExclusions(new FileOfClasses(fs)); - } - + if (exclusionsFile != null) { + try (final InputStream fs = exclusionsFile.exists() ? new FileInputStream(exclusionsFile) : FileProvider.class.getClassLoader().getResourceAsStream(exclusionsFile.getName())) { + scope.setExclusions(new FileOfClasses(fs)); + } + } + scope.setLoaderImpl(ClassLoaderReference.Primordial, "com.ibm.wala.dalvik.classLoader.WDexClassLoaderImpl"); @@ -50,10 +53,7 @@ public class AndroidAnalysisScope { try { scope.addToScope(ClassLoaderReference.Primordial, DexFileModule.make(new File(al))); } catch (Exception e) { - e.printStackTrace(); - try (final JarFile jar = new JarFile(new File(al))) { - scope.addToScope(ClassLoaderReference.Primordial, new JarFileModule(jar)); - } + scope.addToScope(ClassLoaderReference.Primordial, new JarFileModule(new JarFile(new File(al)))); } } diff --git a/com.ibm.wala.scandroid/source/org/scandroid/flow/functions/IFDSTaintFlowFunctionProvider.java b/com.ibm.wala.scandroid/source/org/scandroid/flow/functions/IFDSTaintFlowFunctionProvider.java index 27b2e86e7..a3a3f8270 100644 --- a/com.ibm.wala.scandroid/source/org/scandroid/flow/functions/IFDSTaintFlowFunctionProvider.java +++ b/com.ibm.wala.scandroid/source/org/scandroid/flow/functions/IFDSTaintFlowFunctionProvider.java @@ -436,7 +436,7 @@ implements IFlowFunctionMap> { final SSAInvokeInstruction instruction = (SSAInvokeInstruction) src.getLastInstruction(); // String signature = dest.getMethod().getSignature(); -// if ( dest.getMethod().isSynthetic() ) { +// if ( dest.getMethod().isWalaSynthetic() ) { // System.out.println("Synthetic: "+signature); // } else { // System.err.println(signature); @@ -448,7 +448,7 @@ implements IFlowFunctionMap> { // System.out.println("Call to system: "+signature); // } -// if (! dest.getMethod().isSynthetic() +// if (! dest.getMethod().isWalaSynthetic() // && LoaderUtils.fromLoader(dest.getNode(), ClassLoaderReference.Primordial)) { // // MyLogger.log(DEBUG,"Primordial and No Summary! (getCallFlowFunction) - " + dest.getMethod().getReference()); diff --git a/com.ibm.wala.scandroid/source/org/scandroid/util/CGAnalysisContext.java b/com.ibm.wala.scandroid/source/org/scandroid/util/CGAnalysisContext.java index 42c3a2332..e6a87e51e 100644 --- a/com.ibm.wala.scandroid/source/org/scandroid/util/CGAnalysisContext.java +++ b/com.ibm.wala.scandroid/source/org/scandroid/util/CGAnalysisContext.java @@ -195,7 +195,7 @@ public class CGAnalysisContext { Warnings.clear(); pa = cgb.getPointerAnalysis(); - partialGraph = GraphSlicer.prune(cg, node -> LoaderUtils.fromLoader(node, ClassLoaderReference.Application) || node.getMethod().isSynthetic()); + partialGraph = GraphSlicer.prune(cg, node -> LoaderUtils.fromLoader(node, ClassLoaderReference.Application) || node.getMethod().isWalaSynthetic()); if (options.includeLibrary()) { graph = (ISupergraph) ICFGSupergraph.make(cg); } else { @@ -271,7 +271,7 @@ public class CGAnalysisContext { } } for (CGNode node : Iterator2Iterable.make(cg.iterator())) { - if (node.getMethod().isSynthetic()) { + if (node.getMethod().isWalaSynthetic()) { SSACFG ssaCFG = node.getIR().getControlFlowGraph(); int totalBlocks = ssaCFG.getNumberOfNodes(); for (int i = 0; i < totalBlocks; i++) { diff --git a/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/Constants.java b/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/Constants.java index f86253dde..20e6fcc7c 100644 --- a/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/Constants.java +++ b/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/Constants.java @@ -464,6 +464,8 @@ public interface Constants { public static final short ACC_STRICT = 0x800; + public static final short ACC_SYNTHETIC = 0x1000; + public static final byte CONSTANT_Utf8 = 1; public static final byte CONSTANT_Integer = 3;