Merge branch 'master' of github.com:wala/WALA
This commit is contained in:
commit
31cf42674a
|
@ -256,7 +256,7 @@ public class AstJavaSSAPropagationCallGraphBuilder extends AstSSAPropagationCall
|
||||||
|
|
||||||
System.err.println(("class is " + klass + ", enclosing is " + enclosingClass + ", method is " + node.getMethod()));
|
System.err.println(("class is " + klass + ", enclosing is " + enclosingClass + ", method is " + node.getMethod()));
|
||||||
|
|
||||||
if (node.getMethod().isSynthetic()) {
|
if (node.getMethod().isWalaSynthetic()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,11 @@ abstract public class AstClass implements IClass, ClassConstants {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSynthetic() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getModifiers() {
|
public int getModifiers() {
|
||||||
return modifiers;
|
return modifiers;
|
||||||
|
|
|
@ -91,6 +91,11 @@ abstract public class AstFunctionClass implements IClass, ClassConstants {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSynthetic() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getModifiers() {
|
public int getModifiers() {
|
||||||
return ACC_PUBLIC;
|
return ACC_PUBLIC;
|
||||||
|
|
|
@ -267,6 +267,11 @@ public abstract class AstMethod implements IMethod {
|
||||||
return qualifiers.contains(CAstQualifier.NATIVE);
|
return qualifiers.contains(CAstQualifier.NATIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWalaSynthetic() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSynthetic() {
|
public boolean isSynthetic() {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -141,7 +141,7 @@ public class FactoryBypassInterpreter extends AbstractReflectionInterpreter {
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
throw new IllegalArgumentException("node is null");
|
throw new IllegalArgumentException("node is null");
|
||||||
}
|
}
|
||||||
if (node.getMethod().isSynthetic()) {
|
if (node.getMethod().isWalaSynthetic()) {
|
||||||
SyntheticMethod s = (SyntheticMethod) node.getMethod();
|
SyntheticMethod s = (SyntheticMethod) node.getMethod();
|
||||||
if (s.isFactoryMethod()) {
|
if (s.isFactoryMethod()) {
|
||||||
return getTypesForContext(node.getContext()) != null;
|
return getTypesForContext(node.getContext()) != null;
|
||||||
|
|
|
@ -38,7 +38,7 @@ class FactoryContextSelector implements ContextSelector {
|
||||||
if (callee == null) {
|
if (callee == null) {
|
||||||
throw new IllegalArgumentException("callee is null");
|
throw new IllegalArgumentException("callee is null");
|
||||||
}
|
}
|
||||||
if (callee.isSynthetic()) {
|
if (callee.isWalaSynthetic()) {
|
||||||
SyntheticMethod s = (SyntheticMethod) callee;
|
SyntheticMethod s = (SyntheticMethod) callee;
|
||||||
if (s.isFactoryMethod()) {
|
if (s.isFactoryMethod()) {
|
||||||
return new CallStringContext(new CallString(site, caller.getMethod()));
|
return new CallStringContext(new CallString(site, caller.getMethod()));
|
||||||
|
|
|
@ -371,6 +371,11 @@ public class ArrayClass implements IClass, Constants {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSynthetic() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Reader getSource() {
|
public Reader getSource() {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class CodeScanner {
|
||||||
if (m == null) {
|
if (m == null) {
|
||||||
throw new IllegalArgumentException("m is null");
|
throw new IllegalArgumentException("m is null");
|
||||||
}
|
}
|
||||||
if (m.isSynthetic()) {
|
if (m.isWalaSynthetic()) {
|
||||||
SyntheticMethod sm = (SyntheticMethod) m;
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
return getCallSites(sm.getStatements());
|
return getCallSites(sm.getStatements());
|
||||||
} else {
|
} else {
|
||||||
|
@ -62,7 +62,7 @@ public class CodeScanner {
|
||||||
if (m == null) {
|
if (m == null) {
|
||||||
throw new IllegalArgumentException("m is null");
|
throw new IllegalArgumentException("m is null");
|
||||||
}
|
}
|
||||||
if (m.isSynthetic()) {
|
if (m.isWalaSynthetic()) {
|
||||||
SyntheticMethod sm = (SyntheticMethod) m;
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
return getFieldsRead(sm.getStatements());
|
return getFieldsRead(sm.getStatements());
|
||||||
} else {
|
} else {
|
||||||
|
@ -78,7 +78,7 @@ public class CodeScanner {
|
||||||
if (m == null) {
|
if (m == null) {
|
||||||
throw new IllegalArgumentException("m is null");
|
throw new IllegalArgumentException("m is null");
|
||||||
}
|
}
|
||||||
if (m.isSynthetic()) {
|
if (m.isWalaSynthetic()) {
|
||||||
SyntheticMethod sm = (SyntheticMethod) m;
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
return getFieldsWritten(sm.getStatements());
|
return getFieldsWritten(sm.getStatements());
|
||||||
} else {
|
} else {
|
||||||
|
@ -95,7 +95,7 @@ public class CodeScanner {
|
||||||
if (m == null) {
|
if (m == null) {
|
||||||
throw new IllegalArgumentException("m is null");
|
throw new IllegalArgumentException("m is null");
|
||||||
}
|
}
|
||||||
if (m.isSynthetic()) {
|
if (m.isWalaSynthetic()) {
|
||||||
SyntheticMethod sm = (SyntheticMethod) m;
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
return getArraysWritten(sm.getStatements());
|
return getArraysWritten(sm.getStatements());
|
||||||
} else {
|
} else {
|
||||||
|
@ -111,7 +111,7 @@ public class CodeScanner {
|
||||||
if (m == null) {
|
if (m == null) {
|
||||||
throw new IllegalArgumentException("m is null");
|
throw new IllegalArgumentException("m is null");
|
||||||
}
|
}
|
||||||
if (m.isSynthetic()) {
|
if (m.isWalaSynthetic()) {
|
||||||
SyntheticMethod sm = (SyntheticMethod) m;
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
return getNewSites(sm.getStatements());
|
return getNewSites(sm.getStatements());
|
||||||
} else {
|
} else {
|
||||||
|
@ -123,7 +123,7 @@ public class CodeScanner {
|
||||||
if (m == null) {
|
if (m == null) {
|
||||||
throw new IllegalArgumentException("m is null");
|
throw new IllegalArgumentException("m is null");
|
||||||
}
|
}
|
||||||
if (m.isSynthetic()) {
|
if (m.isWalaSynthetic()) {
|
||||||
SyntheticMethod sm = (SyntheticMethod) m;
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
return hasObjectArrayLoad(sm.getStatements());
|
return hasObjectArrayLoad(sm.getStatements());
|
||||||
} else {
|
} else {
|
||||||
|
@ -135,7 +135,7 @@ public class CodeScanner {
|
||||||
if (m == null) {
|
if (m == null) {
|
||||||
throw new IllegalArgumentException("m is null");
|
throw new IllegalArgumentException("m is null");
|
||||||
}
|
}
|
||||||
if (m.isSynthetic()) {
|
if (m.isWalaSynthetic()) {
|
||||||
SyntheticMethod sm = (SyntheticMethod) m;
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
return hasObjectArrayStore(sm.getStatements());
|
return hasObjectArrayStore(sm.getStatements());
|
||||||
} else {
|
} else {
|
||||||
|
@ -147,7 +147,7 @@ public class CodeScanner {
|
||||||
if (m == null) {
|
if (m == null) {
|
||||||
throw new IllegalArgumentException("m is null");
|
throw new IllegalArgumentException("m is null");
|
||||||
}
|
}
|
||||||
if (m.isSynthetic()) {
|
if (m.isWalaSynthetic()) {
|
||||||
SyntheticMethod sm = (SyntheticMethod) m;
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
return getCaughtExceptions(sm.getStatements());
|
return getCaughtExceptions(sm.getStatements());
|
||||||
} else {
|
} else {
|
||||||
|
@ -166,7 +166,7 @@ public class CodeScanner {
|
||||||
if (m == null) {
|
if (m == null) {
|
||||||
throw new IllegalArgumentException("m is null");
|
throw new IllegalArgumentException("m is null");
|
||||||
}
|
}
|
||||||
if (m.isSynthetic()) {
|
if (m.isWalaSynthetic()) {
|
||||||
SyntheticMethod sm = (SyntheticMethod) m;
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
return iterateCastTypes(sm.getStatements());
|
return iterateCastTypes(sm.getStatements());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -54,6 +54,11 @@ public interface IClass extends IClassHierarchyDweller {
|
||||||
*/
|
*/
|
||||||
boolean isPrivate();
|
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
|
* Return the integer that encodes the class's modifiers, as defined by the JVM specification
|
||||||
*
|
*
|
||||||
|
|
|
@ -43,7 +43,14 @@ public interface IMethod extends IMember, ContextItem {
|
||||||
boolean isNative();
|
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();
|
boolean isSynthetic();
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,15 @@ public abstract class JVMClass<T extends IClassLoader> extends BytecodeClass<T>
|
||||||
return result;
|
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()
|
* @see com.ibm.wala.classLoader.IClass#getClassInitializer()
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -441,7 +441,10 @@ public abstract class ShrikeBTMethod implements IMethod, BytecodeConstants {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSynthetic() {
|
public boolean isSynthetic() { return ((getModifiers() & Constants.ACC_SYNTHETIC) != 0); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWalaSynthetic() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,16 @@ public abstract class SyntheticClass implements IClass {
|
||||||
return false;
|
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()
|
* @see com.ibm.wala.classLoader.IClass#getReference()
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -153,12 +153,20 @@ public class SyntheticMethod implements IMethod {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#isWalaSynthetic()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isWalaSynthetic() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see com.ibm.wala.classLoader.IMethod#isSynthetic()
|
* @see com.ibm.wala.classLoader.IMethod#isSynthetic()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean isSynthetic() {
|
public boolean isSynthetic() {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -102,7 +102,7 @@ public class SimpleMemoryAccessMap implements MemoryAccessMap {
|
||||||
private void populate(CGNode n) {
|
private void populate(CGNode n) {
|
||||||
// we analyze bytecodes to avoid the cost of IR construction, except
|
// we analyze bytecodes to avoid the cost of IR construction, except
|
||||||
// for synthetic methods, where we must use the synthetic IR
|
// 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) {
|
if (DEBUG) {
|
||||||
System.err.println("synthetic method");
|
System.err.println("synthetic method");
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,7 +184,7 @@ public abstract class BasicCallGraph<T> extends AbstractNumberedGraph<CGNode> im
|
||||||
protected NodeImpl(IMethod method, Context C) {
|
protected NodeImpl(IMethod method, Context C) {
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.context = C;
|
this.context = C;
|
||||||
if (method != null && !method.isSynthetic() && method.isAbstract()) {
|
if (method != null && !method.isWalaSynthetic() && method.isAbstract()) {
|
||||||
assert !method.isAbstract() : "Abstract method " + method;
|
assert !method.isAbstract() : "Abstract method " + method;
|
||||||
}
|
}
|
||||||
assert C != null;
|
assert C != null;
|
||||||
|
|
|
@ -297,7 +297,7 @@ public class ExplicitCallGraph extends BasicCallGraph<SSAContextInterpreter> imp
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IR getIR() {
|
public IR getIR() {
|
||||||
if (getMethod().isSynthetic()) {
|
if (getMethod().isWalaSynthetic()) {
|
||||||
// disable local cache in this case, as context interpreters
|
// disable local cache in this case, as context interpreters
|
||||||
// do weird things like mutate IRs
|
// do weird things like mutate IRs
|
||||||
return getCallGraph().getInterpreter(this).getIR(this);
|
return getCallGraph().getInterpreter(this).getIR(this);
|
||||||
|
@ -312,7 +312,7 @@ public class ExplicitCallGraph extends BasicCallGraph<SSAContextInterpreter> imp
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DefUse getDU() {
|
public DefUse getDU() {
|
||||||
if (getMethod().isSynthetic()) {
|
if (getMethod().isWalaSynthetic()) {
|
||||||
// disable local cache in this case, as context interpreters
|
// disable local cache in this case, as context interpreters
|
||||||
// do weird things like mutate IRs
|
// do weird things like mutate IRs
|
||||||
return getCallGraph().getInterpreter(this).getDU(this);
|
return getCallGraph().getInterpreter(this).getDU(this);
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class DefaultIRFactory implements IRFactory<IMethod> {
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
throw new IllegalArgumentException("method cannot be null");
|
throw new IllegalArgumentException("method cannot be null");
|
||||||
}
|
}
|
||||||
if (method.isSynthetic()) {
|
if (method.isWalaSynthetic()) {
|
||||||
return syntheticFactory.makeCFG((SyntheticMethod) method);
|
return syntheticFactory.makeCFG((SyntheticMethod) method);
|
||||||
} else if (method instanceof IBytecodeMethod) {
|
} else if (method instanceof IBytecodeMethod) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -61,7 +61,7 @@ public class DefaultIRFactory implements IRFactory<IMethod> {
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
throw new IllegalArgumentException("method cannot be null");
|
throw new IllegalArgumentException("method cannot be null");
|
||||||
}
|
}
|
||||||
if (method.isSynthetic()) {
|
if (method.isWalaSynthetic()) {
|
||||||
return syntheticFactory.makeIR((SyntheticMethod) method, c, options);
|
return syntheticFactory.makeIR((SyntheticMethod) method, c, options);
|
||||||
} else if (method instanceof IBytecodeMethod) {
|
} else if (method instanceof IBytecodeMethod) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -81,7 +81,7 @@ public class DefaultIRFactory implements IRFactory<IMethod> {
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
throw new IllegalArgumentException("null method");
|
throw new IllegalArgumentException("null method");
|
||||||
}
|
}
|
||||||
if (method.isSynthetic()) {
|
if (method.isWalaSynthetic()) {
|
||||||
return syntheticFactory.contextIsIrrelevant((SyntheticMethod) method);
|
return syntheticFactory.contextIsIrrelevant((SyntheticMethod) method);
|
||||||
} else if (method instanceof ShrikeCTMethod) {
|
} else if (method instanceof ShrikeCTMethod) {
|
||||||
// we know ShrikeFactory contextIsIrrelevant
|
// we know ShrikeFactory contextIsIrrelevant
|
||||||
|
|
|
@ -21,4 +21,5 @@ Export-Package: com.ibm.wala.dalvik.drivers,
|
||||||
com.ibm.wala.dalvik.test.callGraph,
|
com.ibm.wala.dalvik.test.callGraph,
|
||||||
com.ibm.wala.dalvik.test.callGraph.droidbench,
|
com.ibm.wala.dalvik.test.callGraph.droidbench,
|
||||||
com.ibm.wala.dalvik.test.ir,
|
com.ibm.wala.dalvik.test.ir,
|
||||||
|
com.ibm.wala.dalvik.test.cha,
|
||||||
com.ibm.wala.dalvik.test.util
|
com.ibm.wala.dalvik.test.util
|
||||||
|
|
Binary file not shown.
|
@ -144,6 +144,11 @@ public abstract class DroidBenchCGTest extends DalvikCallGraphTestBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Collection<Object[]> generateData(final URI[] androidLibs, final File androidJavaJar, final String filter) {
|
public static Collection<Object[]> generateData(final URI[] androidLibs, final File androidJavaJar, final String filter) {
|
||||||
|
|
||||||
|
return generateData(getDroidBenchRoot(), androidLibs, androidJavaJar, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getDroidBenchRoot(){
|
||||||
String f = walaProperties.getProperty("droidbench.root");
|
String f = walaProperties.getProperty("droidbench.root");
|
||||||
if (f == null || !new File(f).exists()) {
|
if (f == null || !new File(f).exists()) {
|
||||||
f = "/tmp/DroidBench";
|
f = "/tmp/DroidBench";
|
||||||
|
@ -152,7 +157,7 @@ public abstract class DroidBenchCGTest extends DalvikCallGraphTestBase {
|
||||||
System.err.println("Use " + f + " as droid bench root");
|
System.err.println("Use " + f + " as droid bench root");
|
||||||
assert new File(f).exists() : "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";
|
assert new File(f + "/apk/").exists() : "Use " + f + " as droid bench root";
|
||||||
return generateData(f, androidLibs, androidJavaJar, filter);
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Collection<Object[]> generateData(String droidBenchRoot, final URI[] androidLibs, final File androidJavaJar, final String filter) {
|
public static Collection<Object[]> generateData(String droidBenchRoot, final URI[] androidLibs, final File androidJavaJar, final String filter) {
|
||||||
|
|
|
@ -63,9 +63,9 @@ public class JVMLDalvikComparisonTest extends DalvikCallGraphTestBase {
|
||||||
private static Set<Pair<CGNode,CGNode>> edgeDiff(CallGraph from, CallGraph to, boolean userOnly) {
|
private static Set<Pair<CGNode,CGNode>> edgeDiff(CallGraph from, CallGraph to, boolean userOnly) {
|
||||||
Set<Pair<CGNode,CGNode>> result = HashSetFactory.make();
|
Set<Pair<CGNode,CGNode>> result = HashSetFactory.make();
|
||||||
for(CGNode f : from) {
|
for(CGNode f : from) {
|
||||||
if (! f.getMethod().isSynthetic()) {
|
if (! f.getMethod().isWalaSynthetic()) {
|
||||||
outer: for(CGNode t : from) {
|
outer: for(CGNode t : from) {
|
||||||
if (!t.getMethod().isSynthetic() &&
|
if (!t.getMethod().isWalaSynthetic() &&
|
||||||
from.hasEdge(f, t) &&
|
from.hasEdge(f, t) &&
|
||||||
(!userOnly ||
|
(!userOnly ||
|
||||||
!t.getMethod().getDeclaringClass().getClassLoader().getReference().equals(ClassLoaderReference.Primordial)))
|
!t.getMethod().getDeclaringClass().getClassLoader().getReference().equals(ClassLoaderReference.Primordial)))
|
||||||
|
|
|
@ -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<? extends DexBackedDexFile> 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<IClass> 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)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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.pessimisticNullAnalysisForFreeTypeVariables=error
|
||||||
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error
|
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error
|
||||||
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
|
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.rawTypeReference=error
|
||||||
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=error
|
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=error
|
||||||
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=error
|
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=error
|
||||||
|
|
|
@ -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.
|
* @return The DexFile associated to this module.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -51,6 +51,7 @@ import static org.jf.dexlib2.AccessFlags.ABSTRACT;
|
||||||
import static org.jf.dexlib2.AccessFlags.INTERFACE;
|
import static org.jf.dexlib2.AccessFlags.INTERFACE;
|
||||||
import static org.jf.dexlib2.AccessFlags.PRIVATE;
|
import static org.jf.dexlib2.AccessFlags.PRIVATE;
|
||||||
import static org.jf.dexlib2.AccessFlags.PUBLIC;
|
import static org.jf.dexlib2.AccessFlags.PUBLIC;
|
||||||
|
import static org.jf.dexlib2.AccessFlags.SYNTHETIC;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -229,6 +230,13 @@ public class DexIClass extends BytecodeClass<IClassLoader> {
|
||||||
return (modifiers & ABSTRACT.getValue()) != 0;
|
return (modifiers & ABSTRACT.getValue()) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#isAbstract()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isSynthetic() {
|
||||||
|
return (modifiers & SYNTHETIC.getValue()) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
|
|
|
@ -59,6 +59,7 @@ import static org.jf.dexlib2.AccessFlags.PROTECTED;
|
||||||
import static org.jf.dexlib2.AccessFlags.PUBLIC;
|
import static org.jf.dexlib2.AccessFlags.PUBLIC;
|
||||||
import static org.jf.dexlib2.AccessFlags.STATIC;
|
import static org.jf.dexlib2.AccessFlags.STATIC;
|
||||||
import static org.jf.dexlib2.AccessFlags.VOLATILE;
|
import static org.jf.dexlib2.AccessFlags.VOLATILE;
|
||||||
|
import static org.jf.dexlib2.AccessFlags.SYNTHETIC;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -506,14 +507,21 @@ public class DexIMethod implements IBytecodeMethod<Instruction> {
|
||||||
return (eMethod.getAccessFlags() & DECLARED_SYNCHRONIZED.getValue()) != 0;
|
return (eMethod.getAccessFlags() & DECLARED_SYNCHRONIZED.getValue()) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#isWalaSynthetic()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isWalaSynthetic() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see com.ibm.wala.classLoader.IMethod#isSynthetic()
|
* @see com.ibm.wala.classLoader.IMethod#isSynthetic()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean isSynthetic() {
|
public boolean isSynthetic() { return (eMethod.getAccessFlags() & SYNTHETIC.getValue()) != 0; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
|
|
|
@ -33,15 +33,18 @@ public class AndroidAnalysisScope {
|
||||||
|
|
||||||
public static AnalysisScope setUpAndroidAnalysisScope(URI classpath, String exclusions, ClassLoader loader, URI... androidLib) throws IOException {
|
public static AnalysisScope setUpAndroidAnalysisScope(URI classpath, String exclusions, ClassLoader loader, URI... androidLib) throws IOException {
|
||||||
AnalysisScope scope;
|
AnalysisScope scope;
|
||||||
|
File exclusionsFile = exclusions != null? new File(exclusions) : null;
|
||||||
|
|
||||||
if (androidLib == null || androidLib.length == 0) {
|
if (androidLib == null || androidLib.length == 0) {
|
||||||
scope = AnalysisScopeReader.readJavaScope(BASIC_FILE, new File(exclusions), loader);
|
scope = AnalysisScopeReader.readJavaScope(BASIC_FILE, exclusionsFile, loader);
|
||||||
} else {
|
} else {
|
||||||
scope = AnalysisScope.createJavaAnalysisScope();
|
scope = AnalysisScope.createJavaAnalysisScope();
|
||||||
|
|
||||||
File exclusionsFile = new File(exclusions);
|
if (exclusionsFile != null) {
|
||||||
try (final InputStream fs = exclusionsFile.exists()? new FileInputStream(exclusionsFile): FileProvider.class.getClassLoader().getResourceAsStream(exclusionsFile.getName())) {
|
try (final InputStream fs = exclusionsFile.exists() ? new FileInputStream(exclusionsFile) : FileProvider.class.getClassLoader().getResourceAsStream(exclusionsFile.getName())) {
|
||||||
scope.setExclusions(new FileOfClasses(fs));
|
scope.setExclusions(new FileOfClasses(fs));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
scope.setLoaderImpl(ClassLoaderReference.Primordial,
|
scope.setLoaderImpl(ClassLoaderReference.Primordial,
|
||||||
"com.ibm.wala.dalvik.classLoader.WDexClassLoaderImpl");
|
"com.ibm.wala.dalvik.classLoader.WDexClassLoaderImpl");
|
||||||
|
@ -50,10 +53,7 @@ public class AndroidAnalysisScope {
|
||||||
try {
|
try {
|
||||||
scope.addToScope(ClassLoaderReference.Primordial, DexFileModule.make(new File(al)));
|
scope.addToScope(ClassLoaderReference.Primordial, DexFileModule.make(new File(al)));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
scope.addToScope(ClassLoaderReference.Primordial, new JarFileModule(new JarFile(new File(al))));
|
||||||
try (final JarFile jar = new JarFile(new File(al))) {
|
|
||||||
scope.addToScope(ClassLoaderReference.Primordial, new JarFileModule(jar));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -436,7 +436,7 @@ implements IFlowFunctionMap<BasicBlockInContext<E>> {
|
||||||
final SSAInvokeInstruction instruction = (SSAInvokeInstruction) src.getLastInstruction();
|
final SSAInvokeInstruction instruction = (SSAInvokeInstruction) src.getLastInstruction();
|
||||||
|
|
||||||
// String signature = dest.getMethod().getSignature();
|
// String signature = dest.getMethod().getSignature();
|
||||||
// if ( dest.getMethod().isSynthetic() ) {
|
// if ( dest.getMethod().isWalaSynthetic() ) {
|
||||||
// System.out.println("Synthetic: "+signature);
|
// System.out.println("Synthetic: "+signature);
|
||||||
// } else {
|
// } else {
|
||||||
// System.err.println(signature);
|
// System.err.println(signature);
|
||||||
|
@ -448,7 +448,7 @@ implements IFlowFunctionMap<BasicBlockInContext<E>> {
|
||||||
// System.out.println("Call to system: "+signature);
|
// System.out.println("Call to system: "+signature);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// if (! dest.getMethod().isSynthetic()
|
// if (! dest.getMethod().isWalaSynthetic()
|
||||||
// && LoaderUtils.fromLoader(dest.getNode(), ClassLoaderReference.Primordial)) {
|
// && LoaderUtils.fromLoader(dest.getNode(), ClassLoaderReference.Primordial)) {
|
||||||
//
|
//
|
||||||
// MyLogger.log(DEBUG,"Primordial and No Summary! (getCallFlowFunction) - " + dest.getMethod().getReference());
|
// MyLogger.log(DEBUG,"Primordial and No Summary! (getCallFlowFunction) - " + dest.getMethod().getReference());
|
||||||
|
|
|
@ -195,7 +195,7 @@ public class CGAnalysisContext<E extends ISSABasicBlock> {
|
||||||
Warnings.clear();
|
Warnings.clear();
|
||||||
|
|
||||||
pa = cgb.getPointerAnalysis();
|
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()) {
|
if (options.includeLibrary()) {
|
||||||
graph = (ISupergraph) ICFGSupergraph.make(cg);
|
graph = (ISupergraph) ICFGSupergraph.make(cg);
|
||||||
} else {
|
} else {
|
||||||
|
@ -271,7 +271,7 @@ public class CGAnalysisContext<E extends ISSABasicBlock> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (CGNode node : Iterator2Iterable.make(cg.iterator())) {
|
for (CGNode node : Iterator2Iterable.make(cg.iterator())) {
|
||||||
if (node.getMethod().isSynthetic()) {
|
if (node.getMethod().isWalaSynthetic()) {
|
||||||
SSACFG ssaCFG = node.getIR().getControlFlowGraph();
|
SSACFG ssaCFG = node.getIR().getControlFlowGraph();
|
||||||
int totalBlocks = ssaCFG.getNumberOfNodes();
|
int totalBlocks = ssaCFG.getNumberOfNodes();
|
||||||
for (int i = 0; i < totalBlocks; i++) {
|
for (int i = 0; i < totalBlocks; i++) {
|
||||||
|
|
|
@ -464,6 +464,8 @@ public interface Constants {
|
||||||
|
|
||||||
public static final short ACC_STRICT = 0x800;
|
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_Utf8 = 1;
|
||||||
|
|
||||||
public static final byte CONSTANT_Integer = 3;
|
public static final byte CONSTANT_Integer = 3;
|
||||||
|
|
Loading…
Reference in New Issue