This commit is contained in:
Julian Dolby 2015-08-13 11:26:48 -04:00
commit 045537274f
32 changed files with 524 additions and 355 deletions

1
.gitignore vendored
View File

@ -6,6 +6,7 @@
*/bin/*
*~
.metadata/
com.ibm.wala.cast/lib/
com.ibm.wala.cast.java.jdt.test/
com.ibm.wala.cast.java.polyglot/lib/
com.ibm.wala.cast.java.test.data/src/JLex/

View File

@ -59,7 +59,7 @@
<target name="fetchCommonsIo" depends="CommonsIoPresent" unless="commons.io.present">
<delete dir="${temp.folder}"/>
<mkdir dir="${temp.folder}"/>
<get src="http://apache.petsads.us/commons/io/binaries/commons-io-2.4-bin.zip" dest="${temp.folder}/commons-io-2.4.zip"/>
<get src="http://apache.openmirror.de//commons/io/binaries/commons-io-2.4-bin.zip" dest="${temp.folder}/commons-io-2.4.zip"/>
<unzip src="${temp.folder}/commons-io-2.4.zip" dest="${temp.folder}"/>
<copy file="${temp.folder}/commons-io-2.4/commons-io-2.4.jar" tofile="${plugin.destination}/lib/commons-io-2.4.jar" />
<delete dir="${temp.folder}"/>

View File

@ -59,9 +59,10 @@ public interface ExceptionPruningAnalysis<I, T extends IBasicBlock<I>> {
/**
* Returns true if the corresponding method contains instructions that may
* throw an exception. Run compute(IPrograssMonitor) first.
* throw an exception which is not caught in the same method.
* Run compute(IPrograssMonitor) first.
* @return true if the corresponding method contains instructions that may
* throw an exception.
* throw an exception which is not caught in the same method
*/
boolean hasExceptions();

View File

@ -58,7 +58,12 @@ public final class NullPointerAnalysis {
public static ExceptionPruningAnalysis<SSAInstruction, IExplodedBasicBlock>
createIntraproceduralExplodedCFGAnalysis(TypeReference[] ignoredExceptions, IR ir, ParameterState paramState, MethodState mState) {
return new ExplodedCFGNullPointerAnalysis(ignoredExceptions, ir, paramState, mState);
return new ExplodedCFGNullPointerAnalysis(ignoredExceptions, ir, paramState, mState, false);
}
public static ExceptionPruningAnalysis<SSAInstruction, IExplodedBasicBlock>
createIntraproceduralExplodedCFGAnalysis(TypeReference[] ignoredExceptions, IR ir, ParameterState paramState, MethodState mState, boolean optHasException) {
return new ExplodedCFGNullPointerAnalysis(ignoredExceptions, ir, paramState, mState, optHasException);
}
public static ExceptionPruningAnalysis<SSAInstruction, ISSABasicBlock>
@ -86,10 +91,16 @@ public final class NullPointerAnalysis {
computeInterprocAnalysis(final TypeReference[] ignoredExceptions, final CallGraph cg,
final MethodState defaultExceptionMethodState, final IProgressMonitor progress)
throws WalaException, UnsoundGraphException, CancelException {
return computeInterprocAnalysis(ignoredExceptions, cg, defaultExceptionMethodState, progress, false);
}
public static InterprocAnalysisResult<SSAInstruction, IExplodedBasicBlock>
computeInterprocAnalysis(final TypeReference[] ignoredExceptions, final CallGraph cg,
final MethodState defaultExceptionMethodState, final IProgressMonitor progress, boolean optHasExceptions)
throws WalaException, UnsoundGraphException, CancelException {
final InterprocNullPointerAnalysis inpa = InterprocNullPointerAnalysis.compute(ignoredExceptions, cg,
defaultExceptionMethodState, progress);
defaultExceptionMethodState, progress, optHasExceptions);
return inpa.getResult();
}
}

View File

@ -64,20 +64,22 @@ public final class InterprocNullPointerAnalysis {
private final TypeReference[] ignoredExceptions;
private final MethodState defaultMethodState;
private final Map<CGNode, IntraprocAnalysisState> states;
private final boolean optHasExceptions;
public static InterprocNullPointerAnalysis compute(final TypeReference[] ignoredExceptions, final CallGraph cg,
final MethodState defaultMethodState, final IProgressMonitor progress)
final MethodState defaultMethodState, final IProgressMonitor progress, boolean optHasExceptions)
throws WalaException, UnsoundGraphException, CancelException {
final InterprocNullPointerAnalysis inpa = new InterprocNullPointerAnalysis(ignoredExceptions, defaultMethodState);
final InterprocNullPointerAnalysis inpa = new InterprocNullPointerAnalysis(ignoredExceptions, defaultMethodState, optHasExceptions);
inpa.run(cg, progress);
return inpa;
}
private InterprocNullPointerAnalysis(final TypeReference[] ignoredExceptions, final MethodState defaultMethodState) {
private InterprocNullPointerAnalysis(final TypeReference[] ignoredExceptions, final MethodState defaultMethodState, boolean optHasExceptions) {
this.ignoredExceptions = ignoredExceptions;
this.defaultMethodState = defaultMethodState;
this.states = new HashMap<CGNode, IntraprocAnalysisState>();
this.optHasExceptions = optHasExceptions;
}
private void run(final CallGraph cg, final IProgressMonitor progress) throws WalaException, UnsoundGraphException, CancelException {
@ -147,7 +149,7 @@ public final class InterprocNullPointerAnalysis {
// run intraprocedural part again with invoke exception info
final ExceptionPruningAnalysis<SSAInstruction, IExplodedBasicBlock> intra2 =
NullPointerAnalysis.createIntraproceduralExplodedCFGAnalysis(ignoredExceptions, ir, paramState, mState);
NullPointerAnalysis.createIntraproceduralExplodedCFGAnalysis(ignoredExceptions, ir, paramState, mState, optHasExceptions);
final int deletedEdges2 = intra2.compute(progress);
final ControlFlowGraph<SSAInstruction, IExplodedBasicBlock> cfg2 = intra2.getCFG();
final IntraprocAnalysisState singleState1 = states.get(startNode);
@ -174,7 +176,7 @@ public final class InterprocNullPointerAnalysis {
states.put(startNode, new IntraprocAnalysisState());
} else {
final ExceptionPruningAnalysis<SSAInstruction, IExplodedBasicBlock> intra =
NullPointerAnalysis.createIntraproceduralExplodedCFGAnalysis(ignoredExceptions, ir, paramState, defaultMethodState);
NullPointerAnalysis.createIntraproceduralExplodedCFGAnalysis(ignoredExceptions, ir, paramState, defaultMethodState, optHasExceptions);
final int deletedEdges = intra.compute(progress);
// Analyze the method with intraprocedural scope
final ControlFlowGraph<SSAInstruction, IExplodedBasicBlock> cfg = intra.getCFG();

View File

@ -37,12 +37,14 @@ public class ExplodedCFGNullPointerAnalysis implements ExceptionPruningAnalysis<
private final IR ir;
private final ParameterState initialState;
private final MethodState mState;
private final boolean optHasExceptions;
public ExplodedCFGNullPointerAnalysis(TypeReference[] ignoredExceptions, IR ir, ParameterState paramState, MethodState mState) {
public ExplodedCFGNullPointerAnalysis(TypeReference[] ignoredExceptions, IR ir, ParameterState paramState, MethodState mState, boolean optHasExceptions) {
this.ignoredExceptions = (ignoredExceptions != null ? ignoredExceptions.clone() : null);
this.ir = ir;
this.initialState = (paramState == null ? ParameterState.createDefault(ir.getMethod()) : paramState);
this.mState = (mState == null ? MethodState.DEFAULT : mState);
this.optHasExceptions = optHasExceptions;
}
/*
@ -85,7 +87,7 @@ public class ExplodedCFGNullPointerAnalysis implements ExceptionPruningAnalysis<
for (IExplodedBasicBlock bb : cfg) {
if (bb.getInstruction() == null) continue;
List<IExplodedBasicBlock> succ = cfg.getExceptionalSuccessors(bb);
if (succ != null && !succ.isEmpty()) {
if (succ != null && !succ.isEmpty() && (!optHasExceptions || succ.contains(cfg.exit()))) {
hasException = true;
break;
}

View File

@ -634,10 +634,12 @@ public class PropagationSystem extends DefaultFixedPointSolver<PointsToSetVariab
if (getFixedPointSystem() instanceof VerboseAction) {
((VerboseAction) getFixedPointSystem()).performVerboseAction();
}
AbstractStatement s = workList.takeStatement();
System.err.println(printRHSInstances(s));
workList.insertStatement(s);
System.err.println("CGNodes: " + cg.getNumberOfNodes());
if (!workList.isEmpty()) {
AbstractStatement s = workList.takeStatement();
System.err.println(printRHSInstances(s));
workList.insertStatement(s);
System.err.println("CGNodes: " + cg.getNumberOfNodes());
}
}

View File

@ -319,13 +319,15 @@ public class ZeroXInstanceKeys implements InstanceKeyFactory {
return c.getClassHierarchy().isSubclassOf(c, c.getClassHierarchy().lookupClass(TypeReference.JavaLangThrowable));
}
public boolean isStackTraceElement(IClass c) {
public static boolean isStackTraceElement(IClass c) {
if (c == null) {
throw new IllegalArgumentException("C is null");
}
return c.getReference().equals(TypeReference.JavaLangStackTraceElement);
}
private boolean allFieldsArePrimitive(IClass c) {
if (c.isArrayClass()) {
TypeReference t = c.getReference().getArrayElementType();

View File

@ -43,6 +43,7 @@
package com.ibm.wala.ipa.summaries;
import com.ibm.wala.ipa.summaries.MethodSummary;
import com.ibm.wala.ssa.SSAGotoInstruction;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAInstructionFactory;
import com.ibm.wala.ssa.SymbolTable;
@ -289,12 +290,14 @@ public class VolatileMethodSummary {
"to the constructor. This behavior is not supported!");
}
this.locked = true;
for (int i = 0; i < this.instructions.size(); ++i) {
final SSAInstruction inst = this.instructions.get(i);
if ((inst == null) || (inst == RESERVED)) {
if (inst == null) {
if (DEBUG) { System.err.printf("No instruction at iindex {}", i); }
this.summary.addStatement(null);
} else if (inst == RESERVED) {
// replace reserved slots by 'goto next' statements
this.summary.addStatement(new SSAGotoInstruction(i, i+1));
} else {
if (DEBUG) { System.err.printf("Adding @{}: ", inst); }
this.summary.addStatement(inst);
@ -434,10 +437,11 @@ public class VolatileMethodSummary {
* @return A non-reserved writable ProgramCounter
*/
public int getNextProgramCounter() {
while (isUsed(this.currentProgramCounter) || isReserved(this.currentProgramCounter)) {
this.currentProgramCounter++;
while (this.instructions.size() < this.currentProgramCounter) this.instructions.add(null);
int pc = this.currentProgramCounter;
return pc;
}
while (this.instructions.size() < this.currentProgramCounter) this.instructions.add(null);
return this.currentProgramCounter;
}
/**

View File

@ -60,9 +60,10 @@ public class SSAConditionalBranchInstruction extends SSAInstruction {
return operator;
}
@Override
public String toString(SymbolTable symbolTable) {
return "conditional branch(" + operator + ") " + getValueString(symbolTable, val1) + "," + getValueString(symbolTable, val2);
return "conditional branch(" + operator + ", to iindex=" + target + ") " + getValueString(symbolTable, val1) + "," + getValueString(symbolTable, val2);
}
/**

View File

@ -50,9 +50,11 @@ import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.JavaLanguage.JavaInstructionFactory;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.shrikeBT.IConditionalBranchInstruction;
import com.ibm.wala.shrikeBT.IInvokeInstruction;
import com.ibm.wala.ssa.SSAArrayLoadInstruction;
import com.ibm.wala.ssa.SSAArrayStoreInstruction;
import com.ibm.wala.ssa.SSAConditionalBranchInstruction;
import com.ibm.wala.ssa.SSAGetInstruction;
import com.ibm.wala.ssa.SSAGotoInstruction;
import com.ibm.wala.ssa.SSAInvokeInstruction;
@ -612,7 +614,7 @@ public class TypeSafeInstructionFactory {
return true; // TODO
}
private boolean isAssignableFrom(final TypeReference from, final TypeReference to) {
public boolean isAssignableFrom(final TypeReference from, final TypeReference to) {
try {
return ParameterAccessor.isAssignable(from, to, this.cha);
} catch (ClassLookupException e) {
@ -653,6 +655,9 @@ public class TypeSafeInstructionFactory {
return insts.GotoInstruction(iindex, target);
}
public SSAConditionalBranchInstruction ConditionalBranchInstruction(final int iindex, final IConditionalBranchInstruction.IOperator operator, final TypeReference type, final int val1, final int val2, final int target) {
return insts.ConditionalBranchInstruction(iindex, operator, type, val1, val2, target);
}
/**
* result = array[index].
*

View File

@ -7,5 +7,8 @@
<classpathentry exported="true" kind="lib" path="lib/commons-io-2.4.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="lib" path="lib/logback-classic-1.0.9.jar"/>
<classpathentry kind="lib" path="lib/logback-core-1.0.9.jar"/>
<classpathentry kind="lib" path="lib/slf4j-api-1.7.2.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -53,5 +53,9 @@ Bundle-ClassPath: dalvik.jar,
lib/commons-io-2.4.jar,
lib/commons-lang3-3.1.jar,
lib/dexlib-1.3.4.jar,
lib/guava-13.0.1.jar
lib/guava-13.0.1.jar,
lib/logback-classic-1.0.9.jar,
lib/logback-core-1.0.9.jar,
lib/slf4j-api-1.7.2.jar

View File

@ -345,7 +345,7 @@ public class AndroidModel /* makes SummarizedMethod */
final TypeSafeInstructionFactory tsif = new TypeSafeInstructionFactory(this.cha);
final Instantiator instantiator = new Instantiator (this.body, tsif, this.paramManager, this.cha, this.mRef, this.scope);
boolean enteredASection = false;
//
// Add preparing code to the model
//
@ -410,6 +410,7 @@ public class AndroidModel /* makes SummarizedMethod */
if (this.labelSpecial.hadSectionSwitch(ep.order)) {
this.labelSpecial.enter(ep.getSection(), body.getNextProgramCounter());
enteredASection = true;
}
//
@ -554,8 +555,9 @@ public class AndroidModel /* makes SummarizedMethod */
// Close all sections by "jumping over" the remaining labels
labelSpecial.finish(body.getNextProgramCounter());
if (enteredASection) {
labelSpecial.finish(body.getNextProgramCounter());
}
this.monitor.done();
}
@ -736,10 +738,11 @@ public class AndroidModel /* makes SummarizedMethod */
// SHORTCUT:
redirect.addStatement(invokation);
final int returnPC = redirect.getNextProgramCounter();
final SSAInstruction returnInstruction = instructionFactory.ReturnInstruction(returnPC, svc);
redirect.addStatement(returnInstruction);
if (instructionFactory.isAssignableFrom(svc.getType(), svc.getValidIn().getReturnType())) {
final int returnPC = redirect.getNextProgramCounter();
final SSAInstruction returnInstruction = instructionFactory.ReturnInstruction(returnPC, svc);
redirect.addStatement(returnInstruction);
}
final IClass declaringClass = this.cha.lookupClass(asMethod.getDeclaringClass());
if (declaringClass == null) {

View File

@ -1,12 +1,3 @@
/*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*
* This file is a derivative of code released under the terms listed below.
*
*/
/*
* Copyright (c) 2013,
* Tobias Blaschke <code@tobiasblaschke.de>
@ -47,7 +38,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.FieldImpl;
@ -88,36 +81,30 @@ import com.ibm.wala.util.strings.Atom;
* @todo Move this class into an other loader? Currently: Primordial
*/
public final /* singleton */ class AndroidModelClass extends SyntheticClass {
private static Logger logger = LoggerFactory.getLogger(AndroidModelClass.class);
public static final TypeReference ANDROID_MODEL_CLASS = TypeReference.findOrCreate(
ClassLoaderReference.Primordial, TypeName.string2TypeName("Lcom/ibm/wala/AndroidModelClass"));
private static IClassHierarchy cha;
private static class AndroidModelClassHolder {
private static final AndroidModelClass INSTANCE = new AndroidModelClass(AndroidModelClass.cha);
}
private IClassHierarchy cha;
public static AndroidModelClass getInstance(IClassHierarchy cha) {
if (AndroidModelClass.cha == null) {
if (cha == null) {
throw new IllegalArgumentException("Cha may not be null if there had not been an Instance AndroidModelClass before!");
} else {
AndroidModelClass.cha = cha;
}
IClass android = cha.lookupClass(ANDROID_MODEL_CLASS);
AndroidModelClass mClass;
if (android == null) {
mClass = new AndroidModelClass(cha);
} else if (!(android instanceof AndroidModelClass)) {
throw new IllegalArgumentException(String.format("android model class does not have expected type %s, but %s!", AndroidModelClass.class, android.getClass().toString()));
} else {
if (! cha.equals(AndroidModelClass.cha)) {
throw new IllegalArgumentException("Cha differs!");
}
mClass = (AndroidModelClass) android;
}
return AndroidModelClassHolder.INSTANCE;
return mClass;
}
private AndroidModelClass(IClassHierarchy cha) {
super(ANDROID_MODEL_CLASS, cha);
this.addMethod(this.clinit());
if (AndroidModelClassHolder.INSTANCE != null) { // May be caused when using reflection
throw new IllegalStateException("AndroidModelClass is a singleton and already instantiated!");
}
this.cha = cha;
this.cha.addClass(this);
}
/**
@ -193,7 +180,7 @@ public final /* singleton */ class AndroidModelClass extends SyntheticClass {
return methods.get(selector);
}
if (selector.equals(MethodReference.initSelector)) {
logger.warn("AndroidModelClass is not intended to be initialized");
return null;
}
throw new IllegalArgumentException("Could not resolve " + selector);

View File

@ -1,12 +1,3 @@
/*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*
* This file is a derivative of code released under the terms listed below.
*
*/
/*
* Copyright (c) 2013,
* Tobias Blaschke <code@tobiasblaschke.de>
@ -46,7 +37,9 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ibm.wala.analysis.typeInference.ConeType;
import com.ibm.wala.analysis.typeInference.PrimitiveType;
@ -81,6 +74,7 @@ import com.ibm.wala.util.ssa.TypeSafeInstructionFactory;
* @author Tobias Blaschke <code@tobiasblaschke.de>
*/
public class FlatInstantiator implements IInstantiator {
private static final Logger logger = LoggerFactory.getLogger(FlatInstantiator.class);
final IClassHierarchy cha;
final VolatileMethodSummary body;
@ -115,8 +109,8 @@ public class FlatInstantiator implements IInstantiator {
private boolean isExcluded(IClass cls) {
if (this.analysisScope.getExclusions().contains(cls.getName().toString())) { // XXX FUUUUU
if (this.analysisScope.getExclusions() != null && this.analysisScope.getExclusions().contains(cls.getName().toString())) { // XXX FUUUUU
logger.info("Hit exclusions with {}", cls);
return true;
} else {
return false;
@ -145,7 +139,7 @@ public class FlatInstantiator implements IInstantiator {
throw new IllegalArgumentException("Can't create an instance of null");
}
if (seen == null) {
logger.debug("Empty seen");
seen = new HashSet<SSAValue>();
}
@ -189,9 +183,9 @@ public class FlatInstantiator implements IInstantiator {
return instance;
} else if (klass == null) {
if (! T.getName().toString().startsWith("Landroid/")) {
logger.error("The Type {} is not in the ClassHierarchy! Returning null as instance", T);
} else {
logger.debug("The Type {} is not in the ClassHierarchy! Returning null as instance", T);
}
this.body.addConstant(instance.getNumber(), new ConstantValue(null));
instance.setAssigned();
@ -204,7 +198,7 @@ public class FlatInstantiator implements IInstantiator {
final Set<TypeReference> types = getTypes(T);
logger.info("Creating instance of {} is {}", T, types);
if (types.isEmpty()) {
throw new IllegalStateException("Types of " + T + " are empty");
}
@ -220,7 +214,7 @@ public class FlatInstantiator implements IInstantiator {
assert(newInst.getDef() == instance.getNumber());
return instance;
} else if (klass.isArrayClass()) {
logger.info("Creating Array-Class {}", klass.toString());
final TypeReference payloadType = T.getArrayElementType();
SSAValue payload = null;
@ -228,7 +222,7 @@ public class FlatInstantiator implements IInstantiator {
for (final SSAValue see : seen) {
if (ParameterAccessor.isAssignable(see.getType(), payloadType, this.cha)) {
// Happens on Array of interfaces
logger.trace("Reusing {} for array payload {}", see, payload);
payload = see;
}
}
@ -267,7 +261,7 @@ public class FlatInstantiator implements IInstantiator {
return instance;
} else {
// Abstract, Interface or array
logger.debug("Not a regular class {}", T);
final Set<SSAValue> subInstances = new HashSet<SSAValue>();
for (final TypeReference type : types) {
final IClass subKlass = this.cha.lookupClass(type);
@ -330,7 +324,7 @@ public class FlatInstantiator implements IInstantiator {
this.pm.setPhi(instance, phi);
}
} else {
logger.warn("No sub-instances for: {} - setting to null", instance);
this.body.addConstant(instance.getNumber(), new ConstantValue(null));
instance.setAssigned();
}
@ -399,7 +393,7 @@ public class FlatInstantiator implements IInstantiator {
final IMethod cTor = lookupConstructor(val.getType());
final ParameterAccessor ctorAcc = new ParameterAccessor(cTor);
assert (ctorAcc.hasImplicitThis()) : "CTor detected as not having implicit this pointer";
logger.debug("Acc for: %", this.scope);
final ParameterAccessor acc = new ParameterAccessor(this.scope, false); // TODO pm needs a connectThrough too!
// TODO false is false
// TODO: The overrides may lead to use before definition
@ -412,8 +406,8 @@ public class FlatInstantiator implements IInstantiator {
seen.add(nullSelf);
seen.addAll(overrides);
logger.debug("Recursing for: {}", cTor);
logger.debug("With seen: {}", seen);
final List<SSAValue> ctorParams = acc.connectThrough(ctorAcc, overrides, /* defaults */ null, this.cha,
this, /* managed */ false, /* key */ null, seen, currentDepth + 1); // XXX This starts the recursion!
addCallCtor(val, cTor.getReference(), ctorParams);
@ -439,18 +433,19 @@ public class FlatInstantiator implements IInstantiator {
* Used internally to avoid endless recursion on getTypes().
*/
private Set<TypeReference> getTypes(final TypeReference T, final Set<TypeReference> seen) {
logger.debug("getTypes({}, {})", T, seen);
final Set<TypeReference> ret = new HashSet<TypeReference>();
ret.add(T);
if (T.isPrimitiveType()) {
logger.warn("getTypes called on a primitive");
return ret;
//throw new IllegalArgumentException("Not you that call primitive type on :P");
}
final IClass cls = this.cha.lookupClass(T);
if (cls == null) {
logger.error("The type {} is not in the ClassHierarchy - try continuing anyway", T);
return ret;
//throw new IllegalArgumentException("The type " + T + " is not in the ClassHierarchy");
} else if (isExcluded(cls)) {
@ -464,9 +459,9 @@ public class FlatInstantiator implements IInstantiator {
if (impls.isEmpty()) {
//throw new IllegalStateException("The interface " + T + " has no known implementors");
if (! T.getName().toString().startsWith("Landroid/")) {
logger.error("The interface {} has no known implementors - skipping over it", T);
} else {
logger.debug("The interface {} has no known implementors - skipping over it", T);
}
return ret; // XXX: This is a bad idea?
} else {
@ -486,7 +481,7 @@ public class FlatInstantiator implements IInstantiator {
} else {
for (final IClass sub: subs) {
if (seen.contains(sub.getReference())) {
logger.debug("Seen: {}", sub);
continue;
}
if (sub.isAbstract()) {
@ -571,7 +566,7 @@ public class FlatInstantiator implements IInstantiator {
final IMethod method = methods.iterator().next();
assert (method.isInit());
final SSAInstruction firstInstruction = this.cache.getIR(method).iterateAllInstructions().next();
logger.debug("First instruction of ctor is: " + firstInstruction);
if (firstInstruction instanceof SSAAbstractInvokeInstruction) {
final SSAAbstractInvokeInstruction invokation = (SSAAbstractInvokeInstruction) firstInstruction;
return invokation.isSpecial(); // Always?
@ -643,12 +638,12 @@ public class FlatInstantiator implements IInstantiator {
score = candidScore;
}
logger.debug("CTor {} got score {}", im, candidScore);
}
if (ctor == null) {
logger.warn("Still found no CTor for {}", T);
return cha.resolveMethod(klass, MethodReference.initSelector);
} else {
return ctor;

View File

@ -1,12 +1,3 @@
/*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*
* This file is a derivative of code released under the terms listed below.
*
*/
/*
* Copyright (c) 2013,
* Tobias Blaschke <code@tobiasblaschke.de>
@ -46,7 +37,9 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ibm.wala.analysis.typeInference.ConeType;
import com.ibm.wala.analysis.typeInference.PrimitiveType;
@ -85,6 +78,7 @@ import com.ibm.wala.util.strings.Atom;
* @author Tobias Blaschke <code@tobiasblaschke.de>
*/
public class Instantiator implements IInstantiator {
private static final Logger logger = LoggerFactory.getLogger(Instantiator.class);
final IClassHierarchy cha;
final VolatileMethodSummary body;
@ -104,8 +98,8 @@ public class Instantiator implements IInstantiator {
}
private boolean isExcluded(IClass cls) {
if (this.analysisScope.getExclusions().contains(cls.getName().toString())) { // XXX FUUUUU
if (this.analysisScope.getExclusions() != null && this.analysisScope.getExclusions().contains(cls.getName().toString())) { // XXX FUUUUU
logger.info("Hit exclusions with {}", cls);
return true;
} else {
return false;
@ -130,14 +124,14 @@ public class Instantiator implements IInstantiator {
throw new IllegalArgumentException("Can't create an instance of null");
}
if (seen == null) {
logger.debug("Empty seen");
seen = new HashSet<SSAValue>();
}
{ // Special type?
final SpecializedInstantiator sInst = new SpecializedInstantiator(body, instructionFactory, pm,
cha, scope, analysisScope, this);
if (sInst.understands(T)) {
if (SpecializedInstantiator.understands(T)) {
final SpecializedInstantiator sInst = new SpecializedInstantiator(body, instructionFactory, pm,
cha, scope, analysisScope, this);
return sInst.createInstance(T, asManaged, key, seen);
}
}
@ -177,10 +171,10 @@ public class Instantiator implements IInstantiator {
pm.setAllocation(instance, getInst);
return instance;
} else {
logger.info("NEW Component {} \n\tbreadCrumb: {}", instance, pm.breadCrumb);
}
} else {
logger.info("NEW Component {} \n\tbreadCrumb: {}", instance, pm.breadCrumb);
}
}
} // */
@ -190,9 +184,9 @@ public class Instantiator implements IInstantiator {
return instance;
} else if (klass == null) {
if (! T.getName().toString().startsWith("Landroid/")) {
logger.error("The Type {} is not in the ClassHierarchy! Returning null as instance", T);
} else {
logger.debug("The Type {} is not in the ClassHierarchy! Returning null as instance", T);
}
this.body.addConstant(instance.getNumber(), new ConstantValue(null));
instance.setAssigned();
@ -205,7 +199,7 @@ public class Instantiator implements IInstantiator {
final Set<TypeReference> types = getTypes(T);
logger.info("Creating instance of {} is {}", T, types);
if (types.isEmpty()) {
throw new IllegalStateException("Types of " + T + " are empty");
}
@ -221,7 +215,7 @@ public class Instantiator implements IInstantiator {
assert(newInst.getDef() == instance.getNumber());
return instance;
} else if (klass.isArrayClass()) {
logger.info("Creating Array-Class {}", klass.toString());
final TypeReference payloadType = T.getArrayElementType();
SSAValue payload = null;
@ -229,7 +223,7 @@ public class Instantiator implements IInstantiator {
for (final SSAValue see : seen) {
if (ParameterAccessor.isAssignable(see.getType(), payloadType, this.cha)) {
// Happens on Array of interfaces
logger.trace("Reusing {} for array payload {}", see, payload);
payload = see;
}
}
@ -268,7 +262,7 @@ public class Instantiator implements IInstantiator {
return instance;
} else {
// Abstract, Interface or array
logger.debug("Not a regular class {}", T);
final Set<SSAValue> subInstances = new HashSet<SSAValue>();
for (final TypeReference type : types) {
final IClass subKlass = this.cha.lookupClass(type);
@ -331,7 +325,7 @@ public class Instantiator implements IInstantiator {
this.pm.setPhi(instance, phi);
}
} else {
logger.warn("No sub-instances for: {} - setting to null", instance);
this.body.addConstant(instance.getNumber(), new ConstantValue(null));
instance.setAssigned();
}
@ -400,7 +394,7 @@ public class Instantiator implements IInstantiator {
final IMethod cTor = lookupConstructor(val.getType());
final ParameterAccessor ctorAcc = new ParameterAccessor(cTor);
assert (ctorAcc.hasImplicitThis()) : "CTor detected as not having implicit this pointer";
logger.debug("Acc for: %", this.scope);
final ParameterAccessor acc = new ParameterAccessor(this.scope, false); // TODO pm needs a connectThrough too!
// TODO false is false
// TODO: The overrides may lead to use before definition
@ -413,8 +407,8 @@ public class Instantiator implements IInstantiator {
seen.add(nullSelf);
seen.addAll(overrides);
logger.debug("Recursing for: {}", cTor);
logger.debug("With seen: {}", seen);
final List<SSAValue> ctorParams = acc.connectThrough(ctorAcc, overrides, /* defaults */ null, this.cha,
this, /* managed */ false, /* key */ null, seen); // XXX This starts the recursion!
addCallCtor(val, cTor.getReference(), ctorParams);
@ -440,18 +434,19 @@ public class Instantiator implements IInstantiator {
* Used internally to avoid endless recursion on getTypes().
*/
private Set<TypeReference> getTypes(final TypeReference T, final Set<TypeReference> seen) {
logger.debug("getTypes({}, {})", T, seen);
final Set<TypeReference> ret = new HashSet<TypeReference>();
ret.add(T);
if (T.isPrimitiveType()) {
logger.warn("getTypes called on a primitive");
return ret;
//throw new IllegalArgumentException("Not you that call primitive type on :P");
}
final IClass cls = this.cha.lookupClass(T);
if (cls == null) {
logger.error("The type {} is not in the ClassHierarchy - try continuing anyway", T);
return ret;
//throw new IllegalArgumentException("The type " + T + " is not in the ClassHierarchy");
} else if (isExcluded(cls)) {
@ -465,9 +460,9 @@ public class Instantiator implements IInstantiator {
if (impls.isEmpty()) {
//throw new IllegalStateException("The interface " + T + " has no known implementors");
if (! T.getName().toString().startsWith("Landroid/")) {
logger.error("The interface {} has no known implementors - skipping over it", T);
} else {
logger.debug("The interface {} has no known implementors - skipping over it", T);
}
return ret; // XXX: This is a bad idea?
} else {
@ -487,7 +482,7 @@ public class Instantiator implements IInstantiator {
} else {
for (final IClass sub: subs) {
if (seen.contains(sub.getReference())) {
logger.debug("Seen: {}", sub);
continue;
}
if (sub.isAbstract()) {
@ -572,7 +567,7 @@ public class Instantiator implements IInstantiator {
final IMethod method = methods.iterator().next();
assert (method.isInit());
final SSAInstruction firstInstruction = this.cache.getIR(method).iterateAllInstructions().next();
logger.debug("First instruction of ctor is: " + firstInstruction);
if (firstInstruction instanceof SSAAbstractInvokeInstruction) {
final SSAAbstractInvokeInstruction invokation = (SSAAbstractInvokeInstruction) firstInstruction;
return invokation.isSpecial(); // Always?
@ -644,12 +639,12 @@ public class Instantiator implements IInstantiator {
score = candidScore;
}
logger.debug("CTor {} got score {}", im, candidScore);
}
if (ctor == null) {
logger.warn("Still found no CTor for {}", T);
return cha.resolveMethod(klass, MethodReference.initSelector);
} else {
return ctor;

View File

@ -150,7 +150,7 @@ public class SpecializedInstantiator extends FlatInstantiator {
understandTypes.add(AndroidTypes.ContextWrapper);
}
public boolean understands(TypeReference T) {
public static boolean understands(TypeReference T) {
return understandTypes.contains(T);
}

View File

@ -1,12 +1,3 @@
/*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*
* This file is a derivative of code released under the terms listed below.
*
*/
/*
* Copyright (c) 2013,
* Tobias Blaschke <code@tobiasblaschke.de>
@ -43,6 +34,9 @@ package com.ibm.wala.dalvik.ipa.callgraph.androidModel.structure;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ibm.wala.dalvik.ipa.callgraph.impl.AndroidEntryPoint;
import com.ibm.wala.dalvik.ipa.callgraph.impl.AndroidEntryPoint.ExecutionOrder;
import com.ibm.wala.dalvik.ipa.callgraph.impl.AndroidEntryPoint.IExecutionOrder;
@ -73,6 +67,8 @@ import com.ibm.wala.util.ssa.TypeSafeInstructionFactory;
* @since 2013-09-07
*/
public abstract class AbstractAndroidModel {
private static final Logger logger = LoggerFactory.getLogger(AbstractAndroidModel.class);
private ExecutionOrder currentSection = null;
protected VolatileMethodSummary body = null;
protected TypeSafeInstructionFactory insts = null;
@ -84,26 +80,6 @@ public abstract class AbstractAndroidModel {
// Helper functions
//
/**
* Breaks a basic block.
*
* When inserting loops into the model you have to assure a new basic block starts at the
* target of the jump.
* <p>
* An endless loop is a really silly way to do that, but it worked for static analysis.
*
* @return The PC after insertion.
* @deprecated The GoTo instruction breaks basic blocks by itself now, no need to call this
* function any longer
*/
@Deprecated
protected int makeBrakingNOP(int PC) {
body.addStatement(insts.GotoInstruction(PC, PC));
PC++;
return PC;
}
/**
* Return a List of all Types returned by functions between start (inclusive) and end (exclusive).
*
@ -350,7 +326,7 @@ public abstract class AbstractAndroidModel {
if ((this.currentSection != null) && (this.currentSection.compareTo(section) >= 0)) {
if (this.currentSection.compareTo(section) == 0) {
logger.error("You entered {} twice! Ignoring second atempt.", section);
} else {
throw new IllegalArgumentException("Sections must be in ascending order! When trying to " +
"enter " + this.currentSection.toString() + " from " + section.toString());
@ -369,28 +345,28 @@ public abstract class AbstractAndroidModel {
}
if ((this.currentSection == null) &&
(section.compareTo(AndroidEntryPoint.ExecutionOrder.AT_FIRST) >= 0)) {
logger.info("ENTER: AT_FIRST");
PC = enterAT_FIRST(PC);
this.currentSection = AndroidEntryPoint.ExecutionOrder.AT_FIRST;
}
if ((this.currentSection.compareTo(AndroidEntryPoint.ExecutionOrder.AT_FIRST) <= 0) &&
(section.compareTo(AndroidEntryPoint.ExecutionOrder.BEFORE_LOOP) >= 0)) {
logger.info("ENTER: BEFORE_LOOP");
PC = enterBEFORE_LOOP(PC);
this.currentSection = AndroidEntryPoint.ExecutionOrder.BEFORE_LOOP;
}
if ((this.currentSection.compareTo(AndroidEntryPoint.ExecutionOrder.BEFORE_LOOP) <= 0) &&
(section.compareTo(AndroidEntryPoint.ExecutionOrder.START_OF_LOOP) >= 0)) {
logger.info("ENTER: START_OF_LOOP");
PC = enterSTART_OF_LOOP(PC);
this.currentSection = AndroidEntryPoint.ExecutionOrder.START_OF_LOOP;
}
if ((this.currentSection.compareTo(AndroidEntryPoint.ExecutionOrder.START_OF_LOOP) <= 0) &&
(section.compareTo(AndroidEntryPoint.ExecutionOrder.MIDDLE_OF_LOOP) >= 0)) {
logger.info("ENTER: MIDDLE_OF_LOOP");
PC = enterMIDDLE_OF_LOOP(PC);
this.currentSection = AndroidEntryPoint.ExecutionOrder.MIDDLE_OF_LOOP;
}
@ -398,27 +374,27 @@ public abstract class AbstractAndroidModel {
if ((this.currentSection.compareTo(AndroidEntryPoint.ExecutionOrder.MIDDLE_OF_LOOP) <= 0) &&
(section.compareTo(AndroidEntryPoint.ExecutionOrder.MULTIPLE_TIMES_IN_LOOP) >= 0)) {
PC = enterMULTIPLE_TIMES_IN_LOOP(PC);
logger.info("ENTER: MULTIPLE_TIMES_IN_LOOP");
this.currentSection = AndroidEntryPoint.ExecutionOrder.MULTIPLE_TIMES_IN_LOOP;
}
if ((this.currentSection.compareTo(AndroidEntryPoint.ExecutionOrder.MULTIPLE_TIMES_IN_LOOP) <= 0) &&
(section.compareTo(AndroidEntryPoint.ExecutionOrder.END_OF_LOOP) >= 0)) {
logger.info("ENTER: END_OF_LOOP");
PC = enterEND_OF_LOOP(PC);
this.currentSection = AndroidEntryPoint.ExecutionOrder.END_OF_LOOP;
}
if ((this.currentSection.compareTo(AndroidEntryPoint.ExecutionOrder.END_OF_LOOP) <= 0) &&
(section.compareTo(AndroidEntryPoint.ExecutionOrder.AFTER_LOOP) >= 0)) {
logger.info("ENTER: AFTER_LOOP");
PC = enterAFTER_LOOP(PC);
this.currentSection = AndroidEntryPoint.ExecutionOrder.AFTER_LOOP;
}
if ((this.currentSection.compareTo(AndroidEntryPoint.ExecutionOrder.AFTER_LOOP) <= 0) &&
(section.compareTo(AndroidEntryPoint.ExecutionOrder.AT_LAST) >= 0)) {
logger.info("ENTER: AT_LAST");
PC = enterAT_LAST(PC);
this.currentSection = AndroidEntryPoint.ExecutionOrder.AT_LAST;
}

View File

@ -1,12 +1,3 @@
/*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*
* This file is a derivative of code released under the terms listed below.
*
*/
/*
* Copyright (c) 2013,
* Tobias Blaschke <code@tobiasblaschke.de>
@ -44,14 +35,19 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ibm.wala.dalvik.ipa.callgraph.impl.AndroidEntryPoint.ExecutionOrder;
import com.ibm.wala.ipa.callgraph.Entrypoint;
import com.ibm.wala.ipa.summaries.VolatileMethodSummary;
import com.ibm.wala.shrikeBT.IConditionalBranchInstruction;
import com.ibm.wala.ssa.ConstantValue;
import com.ibm.wala.ssa.SSAPhiInstruction;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.ssa.SSAValue;
import com.ibm.wala.util.ssa.SSAValue.NamedKey;
import com.ibm.wala.util.ssa.SSAValue.TypeKey;
import com.ibm.wala.util.ssa.SSAValue.VariableKey;
import com.ibm.wala.util.ssa.SSAValueManager;
@ -74,6 +70,8 @@ import com.ibm.wala.util.ssa.TypeSafeInstructionFactory;
* @author Tobias Blaschke <code@tobiasblaschke.de>
*/
public class LoopAndroidModel extends SingleStartAndroidModel {
private static final Logger logger = LoggerFactory.getLogger(LoopAndroidModel.class);
//protected VolatileMethodSummary body;
//protected JavaInstructionFactory insts;
//protected DexFakeRootMethod.ReuseParameters paramTypes;
@ -98,10 +96,10 @@ public class LoopAndroidModel extends SingleStartAndroidModel {
* {@inheritDoc}
*/
protected int enterSTART_OF_LOOP (int PC) {
logger.info("PC {} is the jump target of START_OF_LOOP", PC);
this.outerLoopPC = PC;
PC = makeBrakingNOP(this.outerLoopPC);
PC = body.getNextProgramCounter();
paramManager.scopeDown(true);
// Top-Half of Phi-Handling
@ -137,7 +135,7 @@ public class LoopAndroidModel extends SingleStartAndroidModel {
// Insert the Phis at the beginning of the Block
int phiPC = outerLoopPC + 1;
boolean oldAllowReserved = body.allowReserved(true);
logger.info("Setting block-inner Phis");
for (TypeReference phiType : outerStartingPhis.keySet()) {
final SSAValue oldPhi = outerStartingPhis.get(phiType);
final List<SSAValue> forPhi = new ArrayList<SSAValue>(2);
@ -152,19 +150,23 @@ public class LoopAndroidModel extends SingleStartAndroidModel {
body.allowReserved(oldAllowReserved);
// Close the Loop
body.addStatement(insts.GotoInstruction(PC, outerLoopPC));
logger.info("Closing Loop");
logger.info("PC {}: Goto {}", PC, outerLoopPC);
NamedKey trueKey = new SSAValue.NamedKey(TypeReference.BooleanName, "true");
SSAValue trueVal = paramManager.getFree(TypeReference.Boolean, trueKey);
paramManager.setPhi(trueVal, null);
body.addConstant(trueVal.getNumber(), new ConstantValue(true));
body.addStatement(insts.ConditionalBranchInstruction(PC, IConditionalBranchInstruction.Operator.EQ, TypeReference.Boolean, trueVal.getNumber(), trueVal.getNumber(), outerLoopPC));
paramManager.scopeUp();
// Add Phi-Statements at the beginning of this block...
logger.info("Setting outer-block Phis");
for (TypeReference phiType : outerStartingPhis.keySet()) {
final VariableKey phiKey = outerStartingPhis.get(phiType).key;
PC = body.getNextProgramCounter();
List<SSAValue> all = paramManager.getAllForPhi(phiKey);
logger.debug("Into phi {} for {}", all, phiType.getName());
// Narf ... unpacking...
paramManager.invalidate(phiKey);
@ -184,7 +186,7 @@ public class LoopAndroidModel extends SingleStartAndroidModel {
* {@inheritDoc}
*/
protected int leaveAT_LAST (int PC) {
logger.info("Leaving Model with PC = {}", PC);
return PC;
}

View File

@ -1,12 +1,3 @@
/*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*
* This file is a derivative of code released under the terms listed below.
*
*/
/*
* Copyright (c) 2013,
* Tobias Blaschke <code@tobiasblaschke.de>
@ -44,14 +35,19 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ibm.wala.dalvik.ipa.callgraph.impl.AndroidEntryPoint.ExecutionOrder;
import com.ibm.wala.ipa.callgraph.Entrypoint;
import com.ibm.wala.ipa.summaries.VolatileMethodSummary;
import com.ibm.wala.shrikeBT.IConditionalBranchInstruction;
import com.ibm.wala.ssa.ConstantValue;
import com.ibm.wala.ssa.SSAPhiInstruction;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.ssa.SSAValue;
import com.ibm.wala.util.ssa.SSAValue.NamedKey;
import com.ibm.wala.util.ssa.SSAValue.TypeKey;
import com.ibm.wala.util.ssa.SSAValue.VariableKey;
import com.ibm.wala.util.ssa.SSAValueManager;
@ -70,6 +66,8 @@ import com.ibm.wala.util.ssa.TypeSafeInstructionFactory;
* @author Tobias Blaschke <code@tobiasblaschke.de>
*/
public class LoopKillAndroidModel extends LoopAndroidModel {
private static final Logger logger = LoggerFactory.getLogger(LoopKillAndroidModel.class);
//protected VolatileMethodSummary body;
//protected JavaInstructionFactory insts;
//protected DexFakeRootMethod.ReuseParameters paramTypes;
@ -92,10 +90,10 @@ public class LoopKillAndroidModel extends LoopAndroidModel {
* {@inheritDoc}
*/
protected int enterAT_FIRST(int PC) {
logger.info("PC {} is the jump target of START_OF_LOOP", PC);
this.outerLoopPC = PC;
PC = makeBrakingNOP(this.outerLoopPC);
PC = body.getNextProgramCounter();
paramManager.scopeDown(true);
// Top-Half of Phi-Handling
@ -131,7 +129,7 @@ public class LoopKillAndroidModel extends LoopAndroidModel {
// Insert the Phis at the beginning of the Block
int phiPC = outerLoopPC + 1;
boolean oldAllowReserved = body.allowReserved(true);
logger.info("Setting block-inner Phis");
for (TypeReference phiType : outerStartingPhis.keySet()) {
final SSAValue oldPhi = outerStartingPhis.get(phiType);
final List<SSAValue> forPhi = new ArrayList<SSAValue>(2);
@ -146,19 +144,23 @@ public class LoopKillAndroidModel extends LoopAndroidModel {
body.allowReserved(oldAllowReserved);
// Close the Loop
body.addStatement(insts.GotoInstruction(PC, outerLoopPC));
logger.info("Closing Loop");
logger.info("PC {}: Goto {}", PC, outerLoopPC);
NamedKey trueKey = new SSAValue.NamedKey(TypeReference.BooleanName, "true");
SSAValue trueVal = paramManager.getFree(TypeReference.Boolean, trueKey);
paramManager.setPhi(trueVal, null);
body.addConstant(trueVal.getNumber(), new ConstantValue(true));
body.addStatement(insts.ConditionalBranchInstruction(PC, IConditionalBranchInstruction.Operator.EQ, TypeReference.Boolean, trueVal.getNumber(), trueVal.getNumber(), outerLoopPC));
paramManager.scopeUp();
// Add Phi-Statements at the beginning of this block...
logger.info("Setting outer-block Phis");
for (TypeReference phiType : outerStartingPhis.keySet()) {
final VariableKey phiKey = outerStartingPhis.get(phiType).key;
PC = body.getNextProgramCounter();
List<SSAValue> all = paramManager.getAllForPhi(phiKey);
logger.debug("Into phi {} for {}", all, phiType.getName());
// Narf ... unpacking...
paramManager.invalidate(phiKey);

View File

@ -1,12 +1,3 @@
/*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*
* This file is a derivative of code released under the terms listed below.
*
*/
/*
* Copyright (c) 2013,
* Tobias Blaschke <code@tobiasblaschke.de>
@ -44,14 +35,19 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ibm.wala.dalvik.ipa.callgraph.impl.AndroidEntryPoint.ExecutionOrder;
import com.ibm.wala.ipa.callgraph.Entrypoint;
import com.ibm.wala.ipa.summaries.VolatileMethodSummary;
import com.ibm.wala.shrikeBT.IConditionalBranchInstruction;
import com.ibm.wala.ssa.ConstantValue;
import com.ibm.wala.ssa.SSAPhiInstruction;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.ssa.SSAValue;
import com.ibm.wala.util.ssa.SSAValue.NamedKey;
import com.ibm.wala.util.ssa.SSAValue.TypeKey;
import com.ibm.wala.util.ssa.SSAValue.VariableKey;
import com.ibm.wala.util.ssa.SSAValueManager;
@ -73,6 +69,8 @@ import com.ibm.wala.util.ssa.TypeSafeInstructionFactory;
* @author Tobias Blaschke <code@tobiasblaschke.de>
*/
public class SingleStartAndroidModel extends AbstractAndroidModel {
private static final Logger logger = LoggerFactory.getLogger(SingleStartAndroidModel.class);
//protected VolatileMethodSummary body;
//protected JavaInstructionFactory insts;
//protected DexFakeRootMethod.ReuseParameters paramTypes;
@ -98,10 +96,9 @@ public class SingleStartAndroidModel extends AbstractAndroidModel {
* {@inheritDoc}
*/
protected int enterMULTIPLE_TIMES_IN_LOOP (int PC) {
logger.info("PC {} is the jump target of START_OF_LOOP", PC);
this.outerLoopPC = PC;
PC = makeBrakingNOP(this.outerLoopPC);
PC = body.getNextProgramCounter();
paramManager.scopeDown(true);
// Top-Half of Phi-Handling
@ -137,7 +134,7 @@ public class SingleStartAndroidModel extends AbstractAndroidModel {
// Insert the Phis at the beginning of the Block
int phiPC = outerLoopPC + 1;
boolean oldAllowReserved = body.allowReserved(true);
logger.info("Setting block-inner Phis");
for (TypeReference phiType : outerStartingPhis.keySet()) {
final SSAValue oldPhi = outerStartingPhis.get(phiType);
final List<SSAValue> forPhi = new ArrayList<SSAValue>(2);
@ -152,19 +149,25 @@ public class SingleStartAndroidModel extends AbstractAndroidModel {
body.allowReserved(oldAllowReserved);
// Close the Loop
body.addStatement(insts.GotoInstruction(PC, outerLoopPC));
logger.info("Closing Loop");
logger.info("PC {}: Goto {}", PC, outerLoopPC);
if (PC != outerLoopPC) {
NamedKey trueKey = new SSAValue.NamedKey(TypeReference.BooleanName, "true");
SSAValue trueVal = paramManager.getFree(TypeReference.Boolean, trueKey);
paramManager.setPhi(trueVal, null);
body.addConstant(trueVal.getNumber(), new ConstantValue(true));
body.addStatement(insts.ConditionalBranchInstruction(PC, IConditionalBranchInstruction.Operator.EQ, TypeReference.Boolean, trueVal.getNumber(), trueVal.getNumber(), outerLoopPC));
}
paramManager.scopeUp();
// Add Phi-Statements at the beginning of this block...
logger.info("Setting outer-block Phis");
for (TypeReference phiType : outerStartingPhis.keySet()) {
final VariableKey phiKey = outerStartingPhis.get(phiType).key;
PC = body.getNextProgramCounter();
List<SSAValue> all = paramManager.getAllForPhi(phiKey);
logger.debug("Into phi {} for {}", all, phiType.getName());
// Narf ... unpacking...
paramManager.invalidate(phiKey);

View File

@ -260,7 +260,7 @@ public class Intent implements ContextItem, Comparable<Intent> {
private static boolean isSystemService(Intent intent) {
assert (intent.action != null);
return ((intent.action.getVal(0) != 'L') && (intent.action.rIndex((byte) '/') < 0) && (intent.action.rIndex((byte) '.') < 0));
return (intent != null && intent.action != null && (intent.action.getVal(0) != 'L') && (intent.action.rIndex((byte) '/') < 0) && (intent.action.rIndex((byte) '.') < 0));
}
/**
@ -311,7 +311,7 @@ public class Intent implements ContextItem, Comparable<Intent> {
// Unknown so not selected as external
return false;
}
return (! intent.action.toString().startsWith(pack));
return (! (intent.action.toString().startsWith("L" + pack) || intent.action.toString().startsWith(pack)));
}
/**

View File

@ -3,8 +3,8 @@
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*
* This file is a derivative of code released under the terms listed below.
*
* This file is a derivative of code released under the terms listed below.
*
*/
/*
@ -40,32 +40,59 @@
*/
package com.ibm.wala.dalvik.ipa.callgraph.propagation.cfa;
import java.util.Map;
import java.util.logging.Logger;
import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.dalvik.ipa.callgraph.propagation.cfa.Intent;
import com.ibm.wala.dalvik.ipa.callgraph.propagation.cfa.IntentMap;
import com.ibm.wala.dalvik.ipa.callgraph.propagation.cfa.IntentContext;
import com.ibm.wala.dalvik.ipa.callgraph.propagation.cfa.AndroidContext;
import com.ibm.wala.dalvik.ipa.callgraph.propagation.cfa.IntentContextInterpreter;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.dalvik.ipa.callgraph.propagation.cfa.IntentStarters.StartInfo;
import com.ibm.wala.dalvik.util.AndroidEntryPointManager;
import com.ibm.wala.dalvik.util.AndroidTypes;
import com.ibm.wala.types.Selector;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.propagation.ConstantKey;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.Selector;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.ipa.callgraph.propagation.NormalAllocationInNode;
import com.ibm.wala.ipa.callgraph.propagation.AbstractTypeInNode;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.util.strings.Atom;
import com.ibm.wala.dalvik.util.AndroidTypes;
import com.ibm.wala.util.intset.EmptyIntSet;
import com.ibm.wala.util.intset.IntSet;
import com.ibm.wala.util.intset.BimodalMutableIntSet;
import com.ibm.wala.util.intset.IntSetUtil;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.dalvik.ipa.callgraph.propagation.cfa.IntentStarters;
import com.ibm.wala.dalvik.ipa.callgraph.propagation.cfa.IntentStarters.StartInfo;
import com.ibm.wala.dalvik.util.AndroidEntryPointManager;
import com.ibm.wala.util.strings.StringStuff;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
import com.ibm.wala.util.collections.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Adds Intents to the Context of functions that start Android-Components.
*
* This is done by remembering all new-sites where Intent-Objects are built and the parameters to its
* Constructor. When a function managed by this Selector (see IntentStarters) is encountered the stored
* Constructor. When a function managed by this Selector (see IntentStarters) is encountered the stored
* information is added to its Context.
*
* @see com.ibm.wala.dalvik.ipa.callgraph.propagation.cfa.IntentContextInterpreter
@ -75,7 +102,9 @@ import com.ibm.wala.util.intset.IntSetUtil;
* @since 2013-10-14
*/
public class IntentContextSelector implements ContextSelector {
private final IntentMap intents = new IntentMap();
private static final Logger logger = LoggerFactory.getLogger(IntentContextSelector.class);
private final IntentMap intents = new IntentMap();
private final ContextSelector parent;
private final IntentStarters intentStarters;
private final Map<InstanceKey, AndroidContext> seenContext;
@ -95,7 +124,7 @@ public class IntentContextSelector implements ContextSelector {
/**
* Given a calling node and a call site, returns the Context in which the callee should be evaluated.
*
*
* {@inheritDoc}
*
* @throws IllegalArgumentException if the type of a parameter given as actualParameters does not match an expected one
@ -116,25 +145,25 @@ public class IntentContextSelector implements ContextSelector {
/* {
final InstanceKey self = actualParameters[0];
assert (self != null) : "This-Pointer was not marked as relevant!";
if (seenContext.containsKey(self)) {
ctx = new AndroidContext(ctx, seenContext.get(self).getContextType());
} else {
logger.warn("No Android-Context seen for {}", caller);
}
} // */
Intent intent = null;
{ // Seach intent
{ // Seach intent
for (int j = 0; j < actualParameters.length; ++j) {
final InstanceKey param = actualParameters[j];
if (param == null) {
continue;
} else if (param.getConcreteType().getName().equals(AndroidTypes.IntentName)) {
} else if (param.getConcreteType().getName().equals(AndroidTypes.IntentName)) {
if (! intents.contains(param) ) {
logger.error("Unable to resolve Intent called from {}", caller.getMethod());
logger.error("Search Key: {} hash: {}", param, param.hashCode());
break;
} else {
intent = intents.find(param);
@ -151,10 +180,10 @@ public class IntentContextSelector implements ContextSelector {
return new IntentContext(ctx, iintent);
//return new IntentContext(iintent);
} else {
logger.warn("Encountered unresolvable Intent");
intent = new Intent("Unresolvable");
intent.setImmutable();
AndroidEntryPointManager.MANAGER.addCallSeen(site, intent);
AndroidEntryPointManager.MANAGER.addCallSeen(site, intent);
return new IntentContext(ctx, intent);
//return new IntentContext(intent);
}
@ -172,21 +201,21 @@ public class IntentContextSelector implements ContextSelector {
return Intent.IntentType.SYSTEM_SERVICE;
}
// TODO override equals and hashCode?
};
};
} else {
intent = null;
if (param == null) {
logger.warn("Got param as 'null'. Obviously can't handle this. Caller was: {}", caller.getMethod());
} else {
logger.warn("Got param as {}. Can't handle this :(", param.getClass());
}
}
}
// Add the context
if (intent != null) {
AndroidEntryPointManager.MANAGER.addCallSeen(site, intent);
AndroidEntryPointManager.MANAGER.addCallSeen(site, intent);
logger.info("SystemService {} in {} by {}", intent, site, caller);
final Intent iintent = intents.findOrCreateImmutable(intent);
return new IntentContext(ctx, iintent);
//return new IntentContext(iintent);
@ -202,57 +231,64 @@ public class IntentContextSelector implements ContextSelector {
final InstanceKey uriKey;
final InstanceKey actionKey;
{ // fetch actionKey, uriKey
switch (callee.getNumberOfParameters()) {
switch (callee.getNumberOfParameters()) {
case 1:
logger.debug("Handling Intent()");
actionKey = null;
uriKey = null;
break;
case 2:
case 2:
if (calleeSel.equals(Selector.make("<init>(Ljava/lang/String;)V"))) {
actionKey = actualParameters[1];
logger.debug("Handling Intent(String action)");
actionKey = actualParameters[1];
} else if (calleeSel.equals(Selector.make("<init>(Landroid/content/Intent;)V"))) {
logger.debug("Handling Intent(Intent other)");
final InstanceKey inIntent = actualParameters[1];
if (intents.contains(inIntent)) {
intents.put(self, intents.find(inIntent));
} else {
logger.warn("In Intent-Copy constructor: Unable to find the original");
}
actionKey = null;
} else {
logger.error("No handling implemented for: {}", callee);
actionKey = null;
}
uriKey = null;
break;
case 3:
if (calleeSel.equals(Selector.make("<init>(Ljava/lang/String;Landroid/net/Uri;)V"))) {
logger.debug("Handling Intent(String action, Uri uri)");
// TODO: Use Information of the URI...
actionKey = actualParameters[1];
actionKey = actualParameters[1];
uriKey = actualParameters[2];
} else if (calleeSel.equals(Selector.make("<init>(Landroid/content/Context;Ljava/lang/Class;)V"))) {
logger.debug("Handling Intent(Context, Class)");
actionKey = actualParameters[2];
uriKey = null;
isExplicit = true;
} else {
logger.error("No handling implemented for: {}", callee);
actionKey = null;
uriKey = null;
}
break;
case 5:
if (calleeSel.equals(Selector.make("<init>(Ljava/lang/String;Landroid/net/Uri;Landroid/content/Context;Ljava/lang/Class;)V"))) {
logger.debug("Handling Intent(String action, Uri uri, Context, Class)");
actionKey = actualParameters[4];
uriKey = actualParameters[2];
isExplicit = true;
} else {
logger.error("No handling implemented for: {}", callee);
actionKey = null;
uriKey = null;
}
break;
default:
logger.error("Can't extract Info from Intent-Constructor: {} (not implemented)", site);
actionKey = null;
uriKey = null;
}
@ -261,9 +297,9 @@ public class IntentContextSelector implements ContextSelector {
final Intent intent = intents.findOrCreate(self); // Creates Wala-internal Intent
if (actionKey == null) {
logger.trace("Got action as 'null'. Obviously can't handle this. Caller was {}", caller.getMethod());
if (isExplicit) {
logger.warn("An Intent with undeteminable target would be explicit - unbinding. Caller was {}", caller.getMethod());
intent.unbind();
}
} else {
@ -274,31 +310,31 @@ public class IntentContextSelector implements ContextSelector {
// intents.setExplicit(self);
//}
logger.debug("Setting the target of Intent {} in {} by {}", intent, site, caller);
// TODO: Evaluate uriKey
} else if (callee.getSelector().equals(Selector.make("setAction(Ljava/lang/String;)Landroid/content/Intent;")) &&
} else if (callee.getSelector().equals(Selector.make("setAction(Ljava/lang/String;)Landroid/content/Intent;")) &&
callee.getDeclaringClass().getName().equals(AndroidTypes.IntentName)) {
final InstanceKey self = actualParameters[0];
final InstanceKey actionKey = actualParameters[1];
final Intent intent = intents.find(self);
if (AndroidEntryPointManager.MANAGER.isAllowIntentRerouting()) {
logger.warn("Re-Setting the target of Intent {} in {} by {}", intent, site, caller);
intents.setAction(self, actionKey, false); // May unbind internally
} else {
intents.unbind(self);
}
logger.info("Encountered Intent.setAction - Intent is now: {}", intent);
} else if (callee.getSelector().equals(Selector.make("setComponent(Landroid/content/ComponentName;)Landroid/content/Intent;"))) {
// TODO: We can't extract from ComponentName yet.
final InstanceKey self = actualParameters[0];
final Intent intent = intents.find(self);
logger.warn("Re-Setting the target of Intent {} in {} by {}", intent, site, caller);
intent.setExplicit();
intents.unbind(self);
} else if (callee.getSelector().equals(Selector.make("setClass(Landroid/content/Context;Ljava/lang/Class;)Landroid/content/Intent;")) ||
} else if (callee.getSelector().equals(Selector.make("setClass(Landroid/content/Context;Ljava/lang/Class;)Landroid/content/Intent;")) ||
callee.getSelector().equals(Selector.make("setClassName(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;")) ||
callee.getSelector().equals(Selector.make("setClassName(Landroid/content/Context;Ljava/lang/String;)Landroid/content/Intent;"))) {
final InstanceKey self = actualParameters[0];
@ -306,51 +342,51 @@ public class IntentContextSelector implements ContextSelector {
final Intent intent = intents.find(self);
if (AndroidEntryPointManager.MANAGER.isAllowIntentRerouting()) {
logger.warn("Re-Setting the target of Intent {} in {} by {}", intent, site, caller);
intents.setAction(self, actionKey, true);
} else {
intents.unbind(self);
}
logger.info("Encountered Intent.setClass - Intent is now: {}", intent);
} else if (callee.getSelector().equals(Selector.make("fillIn(Landroid/content/Intent;I)I"))) {
// See 'setAction' before... TODO
logger.warn("Intent.fillIn not implemented - Caller: {}", caller);
final InstanceKey self = actualParameters[0];
intents.unbind(self);
} else if (callee.isInit() && callee.getDeclaringClass().getName().equals(AndroidTypes.IntentSenderName)) {
// TODO
logger.error("Unable to evaluate IntentSender: Not implemented!"); // TODO
} /*else if (site.isSpecial() && callee.getDeclaringClass().getName().equals(
AndroidTypes.ContextWrapperName)) {
final InstanceKey baseKey = actualParameters[1];
final InstanceKey wrapperKey = actualParameters[0];
final InstanceKey baseKey = actualParameters[1];
final InstanceKey wrapperKey = actualParameters[0];
logger.debug("Handling ContextWrapper(Context base)");
if (seenContext.containsKey(baseKey)) {
seenContext.put(wrapperKey, seenContext.get(baseKey));
} else {
if (baseKey == null) {
logger.trace("Got baseKey as 'null'. Obviously can't handle this. Caller was: {}", caller.getMethod());
} else {
logger.warn("ContextWrapper: No AndroidContext was seen for baseKey");
}
}
} else if ((site.isSpecial() && callee.getDeclaringClass().getName().equals(
AndroidTypes.ContextImplName))) {
final InstanceKey self = actualParameters[0];
seenContext.put(self, new AndroidContext(ctx, AndroidTypes.AndroidContextType.CONTEXT_IMPL));
seenContext.put(self, new AndroidContext(ctx, AndroidTypes.AndroidContextType.CONTEXT_IMPL));
} else if (callee.getDeclaringClass().getName().equals(AndroidTypes.ContextWrapperName) &&
callee.getSelector().equals(Selector.make("attachBaseContext(Landroid/content/Context;)V"))) {
final InstanceKey baseKey = actualParameters[1];
final InstanceKey wrapperKey = actualParameters[0];
final InstanceKey baseKey = actualParameters[1];
final InstanceKey wrapperKey = actualParameters[0];
logger.debug("Handling ContextWrapper.attachBaseContext(base)");
if (seenContext.containsKey(baseKey)) {
seenContext.put(wrapperKey, seenContext.get(baseKey));
} else {
if (baseKey == null) {
logger.trace("Got baseKey as 'null'. Obviously can't handle this. Caller was: {}", caller.getMethod());
} else {
logger.warn("ContextWrapper: No AndroidContext was seen for baseKey");
}
}
} */
@ -359,8 +395,8 @@ public class IntentContextSelector implements ContextSelector {
}
/**
* Given a calling node and a call site, return the set of parameters based on which this selector may choose
* to specialize contexts.
* Given a calling node and a call site, return the set of parameters based on which this selector may choose
* to specialize contexts.
*
* {@inheritDoc}
*/
@ -383,10 +419,10 @@ public class IntentContextSelector implements ContextSelector {
ret = IntSetUtil.add(ret, relevant[i]);
}
}
logger.debug("Get relevant for {} is {}", site, ret);
} else if (site.isSpecial() && target.getDeclaringClass().getName().equals(
AndroidTypes.IntentName)) {
AndroidTypes.IntentName)) {
final MethodReference mRef = site.getDeclaredTarget();
final int numArgs = mRef.getNumberOfParameters();
@ -405,33 +441,44 @@ public class IntentContextSelector implements ContextSelector {
case 1:
return IntSetUtil.make(new int[] { 0, 1 });
case 2:
logger.debug("Got Intent Constructor of: {}", site.getDeclaredTarget().getSelector());
return IntSetUtil.make(new int[] { 0, 1, 2 });
case 3:
logger.debug("Got Intent Constructor of: {}", site.getDeclaredTarget().getSelector());
return IntSetUtil.make(new int[] { 0, 1, 2, 3 });
case 4:
logger.debug("Got Intent Constructor of: {}", site.getDeclaredTarget().getSelector());
return IntSetUtil.make(new int[] { 0, 1, 2, 3, 4 });
default:
logger.debug("Got Intent Constructor of: {}", site.getDeclaredTarget().getSelector());
return IntSetUtil.make(new int[] { 0, 1, 2, 3, 4, 5 });
}
} else if (site.isSpecial() && target.getDeclaringClass().getName().equals(
AndroidTypes.IntentSenderName)) {
// public IntentSender(IIntentSender target)
// public IntentSender(IBinder target)
return IntSetUtil.make(new int[] { 0, 1 });
logger.warn("Encountered an IntentSender-Object: {}", target);
if (target.getNumberOfParameters() == 0) {
// public IntentSender()
return IntSetUtil.make(new int[] { 0 });
} else {
// public IntentSender(IIntentSender target)
// public IntentSender(IBinder target)
return IntSetUtil.make(new int[] { 0, 1 });
}
} /*else if (site.isSpecial() && target.getDeclaringClass().getName().equals(
AndroidTypes.ContextWrapperName)) {
logger.debug("Fetched ContextWrapper ctor");
return IntSetUtil.make(new int[] { 0, 1 });
} else if ((site.isSpecial() && target.getDeclaringClass().getName().equals(
AndroidTypes.ContextImplName))) {
logger.debug("Fetched Context ctor");
return IntSetUtil.make(new int[] { 0 });
} else if (target.getDeclaringClass().getName().equals(AndroidTypes.ContextWrapperName) &&
target.getSelector().equals(Selector.make("attachBaseContext(Landroid/content/Context;)V"))) {
logger.debug("Encountered ContextWrapper.attachBaseContext()");
return IntSetUtil.make(new int[] { 0, 1 });
}*/ else if (target.getSelector().equals(Selector.make("getSystemService(Ljava/lang/String;)Ljava/lang/Object;"))) {
logger.debug("Encountered Context.getSystemService()");
return IntSetUtil.make(new int[] { 0, 1 });
} else if (target.getSelector().equals(Selector.make("setAction(Ljava/lang/String;)Landroid/content/Intent;"))) {
return IntSetUtil.make(new int[] { 0, 1 });

View File

@ -389,8 +389,9 @@ public class DexSSABuilder extends AbstractIntRegisterMachine {
* If we've already created the current instruction, return the value number def'ed by the current instruction. Else, create a
* new symbol.
*/
private int reuseOrCreateDef() {
if (getCurrentInstruction() == null) {
if (getCurrentInstruction() == null || !getCurrentInstruction().hasDef()) {
return symbolTable.newSymbol();
} else {
return getCurrentInstruction().getDef();
@ -766,7 +767,7 @@ public class DexSSABuilder extends AbstractIntRegisterMachine {
*/
@Override
public void visitGoto(Goto instruction) {
emitInstruction(insts.GotoInstruction(getCurrentInstructionIndex(), -1));
emitInstruction(insts.GotoInstruction(getCurrentInstructionIndex(), instruction.destination));
}
/**

View File

@ -1,12 +1,3 @@
/*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*
* This file is a derivative of code released under the terms listed below.
*
*/
/*
* Copyright (c) 2013,
* Tobias Blaschke <code@tobiasblaschke.de>
@ -41,6 +32,7 @@
package com.ibm.wala.dalvik.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@ -50,6 +42,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IClassLoader;
import com.ibm.wala.classLoader.IMethod;
@ -77,6 +72,7 @@ import com.ibm.wala.util.config.SetOfClasses;
* @author Tobias Blaschke <code@tobiasblaschke.de>
*/
public final class AndroidEntryPointLocator {
private static final Logger logger = LoggerFactory.getLogger(AndroidEntryPointLocator.class);
private final IProgressMonitor mon;
/**
@ -176,13 +172,14 @@ nextMethod:
if (this.flags.contains(LocatorFlags.INCLUDE_CALLBACKS)) {
for (final AndroidComponent compo : AndroidComponent.values()) {
if (compo == AndroidComponent.UNKNOWN) continue;
if (compo.toReference() != null) {
if (compo.toReference() == null) {
logger.error("Null-Reference for " + compo);
} else {
bases.add(compo.toReference());
}
}
} else {
// Restrict the set
bases.add(AndroidTypes.Handler);
bases.add(AndroidTypes.Application);
bases.add(AndroidTypes.Activity);
/** @todo TODO: add Fragments in getEntryPoints */
@ -223,6 +220,7 @@ nextMethod:
try {
candids = cha.computeSubClasses(base);
} catch (IllegalArgumentException e) { // Pretty agan :(
logger.error(e.getMessage());
continue;
}
for (final IClass candid : candids) {
@ -236,13 +234,16 @@ nextMethod:
if ((method.isInit() || method.isClinit()) && (! this.flags.contains(LocatorFlags.WITH_CTOR))) {
logger.debug("Skipping constructor of {}", method);
continue;
}
if (baseClass.getMethod(method.getSelector()) != null) {
final AndroidEntryPoint ep = makeEntryPointForHeuristic(method, cha);
if (! eps.contains(ep)) { // Just to be sure that a previous element stays as-is
eps.add(ep);
if (eps.add(ep)) {
logger.debug("Heuristic 1: selecting {} for base {}", method, base);
}
}
}
}
@ -288,7 +289,9 @@ nextMethod:
isAndroidClass = true;
break;
}
logger.trace("Heuristic: \t {} is {}", appClass.getName().toString(), androidClass.getName().toString());
for (IClass iface : appClass.getAllImplementedInterfaces ()) {
logger.trace("Heuristic: \t implements {}", iface.getName().toString());
if (isAPIComponent(iface)) {
isAndroidClass = true;
break;
@ -298,16 +301,19 @@ nextMethod:
androidClass = androidClass.getSuperclass();
}
if (! isAndroidClass) {
logger.trace("Heuristic: Skipping non andoid {}", appClass.getName().toString());
continue; // continue appClass;
}
}
logger.debug("Heuristic: Scanning methods of {}", appClass.getName().toString());
{ // Overridden methods
if (isAPIComponent(appClass)) continue;
if (isExcluded(appClass)) continue;
final Collection<IMethod> methods = appClass.getDeclaredMethods();
for (final IMethod method : methods) {
if ((method.isInit() || method.isClinit()) && (! this.flags.contains(LocatorFlags.WITH_CTOR))) {
logger.debug("Skipping constructor of {}", method);
continue;
}
assert (method.getSelector() != null): "Method has no selector: " + method;
@ -316,7 +322,10 @@ nextMethod:
final AndroidEntryPoint ep = makeEntryPointForHeuristic(method, cha);
if (! eps.contains(ep)) { // Just to be sure that a previous element stays as-is
eps.add(ep);
if (eps.add(ep)) {
logger.debug("Heuristic 2a: selecting {}", method);
}} else {
logger.debug("Heuristic 2a: already selected {}", method);
}
}
}
@ -326,22 +335,22 @@ nextMethod:
final Collection<IClass> iFaces = appClass.getAllImplementedInterfaces();
for (final IClass iFace : iFaces) {
if (isAPIComponent(iFace)) {
logger.debug("Skipping iFace: {}", iFace);
continue;
}
if (isExcluded(iFace)) continue;
logger.debug("Searching Interface {}", iFace);
final Collection<IMethod> ifMethods = iFace.getDeclaredMethods();
for (final IMethod ifMethod : ifMethods) {
final IMethod method = appClass.getMethod(ifMethod.getSelector());
if (method == null || method.isAbstract()) {
continue;
}
if (method.getDeclaringClass().getClassLoader().getReference().equals(ClassLoaderReference.Application)) {
if (method != null && method.getDeclaringClass().getClassLoader().getReference().equals(ClassLoaderReference.Application)) {
// The function is overridden
final AndroidEntryPoint ep = new AndroidEntryPoint(selectPositionForHeuristic(method), method, cha);
if (! eps.contains(ep)) { // Just to be sure that a previous element stays as-is
eps.add(ep);
}
if (eps.add(ep)) {
logger.debug("Heuristic 2b: selecting {}", method);
}}
} else {
// The function is taken from the super-class
if (this.flags.contains(LocatorFlags.WITH_SUPER)) {
@ -356,6 +365,7 @@ nextMethod:
System.arraycopy(oldTypes, 0, newTypes, 0, oldTypes.length);
newTypes[oldTypes.length] = appClass.getReference();
eps_ep.setParameterTypes(0, newTypes);
logger.debug("New This-Types for {} are {}", method.getSelector(), Arrays.toString(newTypes));
}
}
} else {
@ -363,7 +373,10 @@ nextMethod:
ep.setParameterTypes(0, new TypeReference[]{appClass.getReference()});
}
eps.add(ep);
logger.debug("Heuristic 2b: selecting from super {}", method);
}
} else {
logger.debug("Heuristic 2b: Skipping {}", method);
}
}
}
@ -389,9 +402,12 @@ nextMethod:
private boolean isExcluded(final IClass cls) {
final SetOfClasses set = cls.getClassHierarchy().getScope().getExclusions();
final String clsName = cls.getReference().getName().toString().substring(1);
return set.contains(clsName);
if (set == null) {
return false; // exclusions null ==> no exclusions ==> no class is excluded
} else {
final String clsName = cls.getReference().getName().toString().substring(1);
return set.contains(clsName);
}
}
/**

View File

@ -1,12 +1,3 @@
/*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*
* This file is a derivative of code released under the terms listed below.
*
*/
/*
* Copyright (c) 2013,
* Tobias Blaschke <code@tobiasblaschke.de>
@ -49,6 +40,9 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.dalvik.ipa.callgraph.androidModel.parameters.DefaultInstantiationBehavior;
import com.ibm.wala.dalvik.ipa.callgraph.androidModel.parameters.IInstantiationBehavior;
@ -76,7 +70,9 @@ import com.ibm.wala.util.strings.StringStuff;
* @author Tobias Blaschke <code@tobiasblaschke.de>
*/
public final /* singleton */ class AndroidEntryPointManager implements Serializable {
public static final AndroidEntryPointManager MANAGER = new AndroidEntryPointManager();
private static final Logger logger = LoggerFactory.getLogger(AndroidEntryPointManager.class);
public static AndroidEntryPointManager MANAGER = new AndroidEntryPointManager();
public static List<AndroidEntryPoint> ENTRIES = new ArrayList<AndroidEntryPoint>();
/**
* This is TRANSIENT!
@ -98,7 +94,12 @@ public final /* singleton */ class AndroidEntryPointManager implements Serializa
return false;
}
private AndroidEntryPointManager() {}
private AndroidEntryPointManager() {}
public static void reset() {
ENTRIES = new ArrayList<AndroidEntryPoint>();
MANAGER = new AndroidEntryPointManager();
}
public Set<TypeReference> getComponents() {
if (ENTRIES.isEmpty()) {
@ -242,7 +243,7 @@ public final /* singleton */ class AndroidEntryPointManager implements Serializa
return prev;
}
private Class<? extends AbstractAndroidModel> abstractAndroidModel = LoopAndroidModel.class;
private Class abstractAndroidModel = LoopAndroidModel.class;
/**
* What special handling to insert into the model.
*
@ -261,7 +262,7 @@ public final /* singleton */ class AndroidEntryPointManager implements Serializa
return new LoopAndroidModel(body, insts, paramManager, entryPoints);
} else {
try {
final Constructor<? extends AbstractAndroidModel> ctor = this.abstractAndroidModel.getDeclaredConstructor(
final Constructor<AbstractAndroidModel> ctor = this.abstractAndroidModel.getDeclaredConstructor(
VolatileMethodSummary.class, TypeSafeInstructionFactory.class, SSAValueManager.class,
Iterable.class);
if (ctor == null) {
@ -290,7 +291,7 @@ public final /* singleton */ class AndroidEntryPointManager implements Serializa
*
* @return null or the class set using setModelBehavior
*/
public Class<?> getModelBehavior() {
public Class getModelBehavior() {
return this.abstractAndroidModel;
}
@ -299,7 +300,7 @@ public final /* singleton */ class AndroidEntryPointManager implements Serializa
*
* @throws IllgealArgumentException if the abstractAndroidModel does not subclass AbstractAndroidModel
*/
public void setModelBehavior(Class<? extends AbstractAndroidModel> abstractAndroidModel) {
public void setModelBehavior(Class abstractAndroidModel) {
if (abstractAndroidModel == null) {
throw new IllegalArgumentException("abstractAndroidModel may not be null. Use SequentialAndroidModel " +
"if no special handling shall be inserted.");
@ -336,6 +337,7 @@ public final /* singleton */ class AndroidEntryPointManager implements Serializa
pack = StringStuff.deployment2CanonicalTypeString(pack);
}
if (this.pack == null) {
logger.info("Setting the package to {}", pack);
this.pack = pack;
} else if (!(this.pack.equals(pack))) {
throw new IllegalArgumentException("The already set package " + this.pack + " and " + pack +
@ -359,6 +361,7 @@ public final /* singleton */ class AndroidEntryPointManager implements Serializa
*/
public String getPackage() {
if (this.pack == null) {
logger.warn("Returning null as package");
return null;
} else {
return this.pack;
@ -379,7 +382,7 @@ public final /* singleton */ class AndroidEntryPointManager implements Serializa
return this.pack;
} else {
if (ENTRIES.isEmpty()) {
assert false : "guessPackage() called when no entrypoints had been set";
logger.error("guessPackage() called when no entrypoints had been set");
return null;
}
final String first = ENTRIES.get(0).getMethod().getReference().getDeclaringClass().getName().getPackage().toString();
@ -446,6 +449,7 @@ public final /* singleton */ class AndroidEntryPointManager implements Serializa
throw new IllegalArgumentException("The given Intent is null");
}
logger.info("Register Intent {}", intent);
// Looks a bit weired but works as Intents are only matched based on their action and uri
overrideIntents.put(intent, intent);
}
@ -559,6 +563,7 @@ public final /* singleton */ class AndroidEntryPointManager implements Serializa
throw new IllegalArgumentException("The Intent given as 'to' is null");
}
logger.info("Override Intent {} to {}", from, to);
overrideIntents.put(from, to);
}
@ -581,20 +586,28 @@ public final /* singleton */ class AndroidEntryPointManager implements Serializa
while (!(ret.equals(intent))) {
// Follow the chain of overrides
if (!overrideIntents.containsKey(intent)) {
logger.info("Resolved {} to {}", intent, ret);
return ret;
} else {
logger.debug("Resolving {} hop over {}", intent, ret);
final Intent old = ret;
ret = overrideIntents.get(ret);
if (ret == old) { // Yes, ==
// This is an evil hack(tm). I should fix the Intent-Table!
logger.warn("Malformend Intent-Table, staying with " + ret + " for " + intent);
return ret;
}
}
}
ret = overrideIntents.get(ret); // Once again to get Info set in register
logger.info("Resolved {} to {}", intent, ret);
return ret;
} else {
logger.info("No information on {} hash: {}", intent, intent.hashCode());
for (Intent known : overrideIntents.keySet()) {
logger.debug("Known Intents: {} hash: {}", known, known.hashCode());
}
return intent;
}
}

View File

@ -55,6 +55,8 @@ import java.util.Stack;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@ -93,6 +95,8 @@ public class AndroidManifestXMLReader {
* If you only want Information about objects created use the logger in AndroidSettingFactory as this
* parser generates all objects using it.
*/
private static final Logger logger = LoggerFactory.getLogger(AndroidSettingFactory.class);
public AndroidManifestXMLReader(File xmlFile) throws IOException {
if (xmlFile == null) {
throw new IllegalArgumentException("xmlFile may not be null");
@ -417,6 +421,7 @@ public class AndroidManifestXMLReader {
}
attributesHistory.get(relevant).push(attr);
logger.debug("Pushing '{}' for {} in {}", attr, relevant, self);
// if there is no such value in saxAttrs it returns null
}
}
@ -428,6 +433,7 @@ public class AndroidManifestXMLReader {
public void popAttributes() {
for (Attr relevant : self.getRelevantAttributes()) {
try {
logger.debug("Popping {} of value {} in {}", relevant, attributesHistory.get(relevant).peek(), self);
attributesHistory.get(relevant).pop();
} catch (java.util.EmptyStackException e) {
System.err.println(self + " failed to pop " + relevant);
@ -461,6 +467,7 @@ public class AndroidManifestXMLReader {
}
subTag.getHandler().popAttributes(); // hmmm....
logger.debug("New Stack: {}", parserStack);
//parserStack.pop();
} else {
throw new IllegalStateException(subTag + " is not allowed as sub-tag of " + self + " in Context:\n\t" + parserStack);
@ -531,20 +538,18 @@ public class AndroidManifestXMLReader {
@Override
public void leave() {
Set<Tag> allowedTags = EnumSet.copyOf(self.getAllowedSubTags());
String url = null;
String name = null;
Set<String> urls = new HashSet<String>();
Set<String> names = new HashSet<String>();
while (parserStack.peek() != self) {
Tag current = parserStack.pop();
if (allowedTags.contains(current)) {
allowedTags.remove(current); // TODO: Does this always fit?
if (current == Tag.ACTION) {
Object oName = attributesHistory.get(Attr.NAME).peek();
if (oName == null) {
throw new IllegalStateException("The currently parsed Action did not leave the required 'name' Attribute" +
" on the Stack! Attributes-Stack for name is: " + attributesHistory.get(Attr.NAME));
} else if (oName instanceof String) {
name = (String) oName;
names.add((String) oName);
} else {
throw new IllegalStateException("Unexpected Attribute type for name: " + oName.getClass().toString());
}
@ -553,7 +558,7 @@ public class AndroidManifestXMLReader {
if (oUrl == null) {
// TODO
} else if (oUrl instanceof String) {
url = (String) oUrl;
urls.add((String) oUrl);
} else {
throw new IllegalStateException("Unexpected Attribute type for name: " + oUrl.getClass().toString());
}
@ -572,12 +577,19 @@ public class AndroidManifestXMLReader {
if ((attributesHistory.get(Attr.PACKAGE) != null ) && (!(attributesHistory.get(Attr.PACKAGE).isEmpty()))) {
pack = (String) attributesHistory.get(Attr.PACKAGE).peek();
} else {
logger.warn("Empty Package {}", attributesHistory.get(Attr.PACKAGE).peek());
pack = null;
}
if (name != null) {
final Intent intent = AndroidSettingFactory.intent(name, url);
attributesHistory.get(self).push(intent);
if (!names.isEmpty()) {
for (String name : names) {
if (urls.isEmpty()) urls.add(null);
for (String url : urls) {
logger.info("New Intent ({}, {})", name, url);
final Intent intent = AndroidSettingFactory.intent(name, url);
attributesHistory.get(self).push(intent);
}
}
} else {
throw new IllegalStateException("Error in parser implementation! The required attribute 'name' which should have been " +
"defined in ACTION could not be retrieved. This should have been thrown before as it is a required attribute for " +
@ -623,13 +635,16 @@ public class AndroidManifestXMLReader {
if ((attributesHistory.get(Attr.PACKAGE) != null ) && (!(attributesHistory.get(Attr.PACKAGE).isEmpty()))) {
pack = (String) attributesHistory.get(Attr.PACKAGE).peek();
} else {
logger.warn("Empty Package {}", attributesHistory.get(Attr.PACKAGE).peek());
pack = null;
}
final String name = (String) attributesHistory.get(Attr.NAME).peek(); // TODO: Verify type!
final Intent intent = AndroidSettingFactory.intent(pack, name, null);
logger.info("\tRegister: {}", intent);
AndroidEntryPointManager.MANAGER.registerIntent(intent);
for (Intent ovr: overrideTargets) {
logger.info("\tOverride: {} --> {}", ovr, intent);
AndroidEntryPointManager.MANAGER.setOverride(ovr, intent);
}
}
@ -649,7 +664,9 @@ public class AndroidManifestXMLReader {
if ((tag == Tag.UNIMPORTANT) || (unimportantDepth > 0)) {
unimportantDepth++;
} else {
final ParserItem handler = tag.getHandler();
logger.debug("Handling {} made from {}", tag, qName);
final ParserItem handler = tag.getHandler();
if (handler != null) {
handler.enter(attrs);
}

View File

@ -225,7 +225,7 @@ public class AndroidPreFlightChecks {
public boolean checkAllComponentsReuse() {
boolean pass = true;
final IInstantiationBehavior behaviour = this.manager.getInstantiationBehavior(null); // XXX: This generates false positives without cha!
final IInstantiationBehavior behaviour = this.manager.getInstantiationBehavior(cha); // XXX: This generates false positives without cha!
final List <AndroidEntryPoint> entrypoits = AndroidEntryPointManager.ENTRIES;
for (AndroidEntryPoint ep : entrypoits) {

View File

@ -23,7 +23,7 @@ public class BasicNullaryStatement<T extends IVariable> extends NullaryStatement
*/
private final NullaryOperator<T> operator;
BasicNullaryStatement(T lhs, NullaryOperator<T> operator) {
public BasicNullaryStatement(T lhs, NullaryOperator<T> operator) {
super(lhs);
this.operator = operator;
}
@ -35,4 +35,20 @@ public class BasicNullaryStatement<T extends IVariable> extends NullaryStatement
public NullaryOperator<T> getOperator() {
return operator;
}
/**
* Return a string representation of this object
* @return a string representation of this object
*/
@Override
public String toString() {
String result;
if (lhs == null) {
result = "null lhs";
} else {
result = lhs.toString();
}
result = getOperator() + " " + result;
return result;
}
}

View File

@ -43,6 +43,9 @@ public class FileOfClasses extends SetOfClasses implements Serializable {
StringBuffer regex = null;
String line;
while ((line = is.readLine()) != null) {
if (line.startsWith("#")) continue;
if (regex == null) {
regex = new StringBuffer("(" + line + ")");
} else {

View File

@ -11,8 +11,10 @@
package com.ibm.wala.util.graph;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Stack;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.intset.BasicNaturalRelation;
@ -40,6 +42,8 @@ public class Acyclic {
return !it.hasNext();
}
public static final int THRESHOLD_FOR_NONRECURSIVE_DFS = 1000;
/**
* Compute a relation R s.t. (i,j) \in R iff (i,j) is a backedge according to a DFS of a numbered graph starting from some root.
*
@ -49,14 +53,23 @@ public class Acyclic {
if (G == null) {
throw new IllegalArgumentException("G is null");
}
BasicNaturalRelation result = new BasicNaturalRelation();
final BasicNaturalRelation result = new BasicNaturalRelation();
Set<T> visited = HashSetFactory.make();
Set<T> onstack = HashSetFactory.make();
dfs(result, root, G, visited, onstack);
// for large methods (e.g. obfuscated library code as found in android libraries 'com.google.ads.ad.a([B[B)V')
// the recursive dfs can lead to a stack overflow error.
// for smaller methods the recursive solution seems to be faster, so we keep it.
if (G.getNumberOfNodes() <= THRESHOLD_FOR_NONRECURSIVE_DFS) {
final Set<T> visited = HashSetFactory.make();
final Set<T> onstack = HashSetFactory.make();
dfs(result, root, G, visited, onstack);
} else {
dfsNonRecursive(result, root, G);
}
return result;
}
private static <T> void dfs(BasicNaturalRelation result, T root, NumberedGraph<T> G, Set<T> visited, Set<T> onstack) {
visited.add(root);
onstack.add(root);
@ -74,6 +87,48 @@ public class Acyclic {
onstack.remove(root);
}
private static <T> void dfsNonRecursive(final BasicNaturalRelation result, final T root, final NumberedGraph<T> G) {
final Stack<T> stack = new Stack<T>();
final Set<T> stackSet = new HashSet<T>();
final Stack<Iterator<? extends T>> stackIt = new Stack<Iterator<? extends T>>();
final Set<T> finished = new HashSet<T>();
stack.push(root);
stackSet.add(root);
stackIt.push(G.getSuccNodes(root));
while (!stack.isEmpty()) {
final T current = stack.pop();
stackSet.remove(current);
final Iterator<? extends T> currentIt = stackIt.pop();
if (finished.contains(current)) { continue; }
boolean isFinished = true;
while (isFinished && currentIt.hasNext() ) {
final T succ = currentIt.next();
if (!finished.contains(succ)) {
if (succ == current || stackSet.contains(succ)) {
// found a backedge
final int src = G.getNumber(current);
final int dst = G.getNumber(succ);
result.add(src, dst);
} else {
stack.push(current);
stackSet.add(current);
stackIt.push(currentIt);
stack.push(succ);
stackSet.add(succ);
stackIt.push(G.getSuccNodes(succ));
isFinished = false;
}
}
}
if (isFinished) {
finished.add(current);
}
}
}
public static <T> boolean hasIncomingBackEdges(Path p, NumberedGraph<T> G, T root) {
/*
* TODO: pull out computeBackEdges, and pass in the backedge relation as a parameter to this call