From 485b02a8e0d105fa067470a7f0c1f59a023244e3 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Thu, 20 Nov 2014 14:51:59 +0100 Subject: [PATCH 01/42] instantiate SpecializedInstanstiator only if given class is really special --- .../ipa/callgraph/androidModel/parameters/Instantiator.java | 6 +++--- .../androidModel/parameters/SpecializedInstantiator.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/Instantiator.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/Instantiator.java index a866cc740..6bb79f440 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/Instantiator.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/Instantiator.java @@ -135,9 +135,9 @@ public class Instantiator implements IInstantiator { } { // 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); } } diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/SpecializedInstantiator.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/SpecializedInstantiator.java index 6adc5e780..860c2087e 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/SpecializedInstantiator.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/SpecializedInstantiator.java @@ -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); } From 86c65f05789cbe5b69415080ec16ada29582c9a6 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 21 Nov 2014 17:24:36 +0100 Subject: [PATCH 02/42] fix some issues of the IntentContextSelector --- .../cfa/IntentContextSelector.java | 138 +++++++++++------- 1 file changed, 88 insertions(+), 50 deletions(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/IntentContextSelector.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/IntentContextSelector.java index 756669046..a83c52ef9 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/IntentContextSelector.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/IntentContextSelector.java @@ -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 @@ -40,26 +31,53 @@ */ 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. @@ -75,7 +93,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 seenContext; @@ -120,7 +140,7 @@ public class IntentContextSelector implements ContextSelector { if (seenContext.containsKey(self)) { ctx = new AndroidContext(ctx, seenContext.get(self).getContextType()); } else { - + logger.warn("No Android-Context seen for {}", caller); } } // */ @@ -133,8 +153,8 @@ public class IntentContextSelector implements ContextSelector { continue; } 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,7 +171,7 @@ 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); @@ -176,9 +196,9 @@ public class IntentContextSelector implements ContextSelector { } 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()); } } } @@ -186,7 +206,7 @@ public class IntentContextSelector implements ContextSelector { // Add the context if (intent != null) { 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); @@ -204,55 +224,62 @@ public class IntentContextSelector implements ContextSelector { { // fetch actionKey, uriKey switch (callee.getNumberOfParameters()) { case 1: + logger.debug("Handling Intent()"); actionKey = null; uriKey = null; break; case 2: if (calleeSel.equals(Selector.make("(Ljava/lang/String;)V"))) { + logger.debug("Handling Intent(String action)"); actionKey = actualParameters[1]; } else if (calleeSel.equals(Selector.make("(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("(Ljava/lang/String;Landroid/net/Uri;)V"))) { + logger.debug("Handling Intent(String action, Uri uri)"); // TODO: Use Information of the URI... actionKey = actualParameters[1]; uriKey = actualParameters[2]; } else if (calleeSel.equals(Selector.make("(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("(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 +288,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,7 +301,7 @@ 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;")) && callee.getDeclaringClass().getName().equals(AndroidTypes.IntentName)) { @@ -283,18 +310,18 @@ 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, 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); @@ -306,19 +333,19 @@ 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]; @@ -329,9 +356,9 @@ public class IntentContextSelector implements ContextSelector { 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( @@ -348,9 +375,9 @@ public class IntentContextSelector implements ContextSelector { 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"); } } } */ @@ -384,7 +411,7 @@ public class IntentContextSelector implements ContextSelector { } } - + logger.debug("Get relevant for {} is {}", site, ret); } else if (site.isSpecial() && target.getDeclaringClass().getName().equals( AndroidTypes.IntentName)) { @@ -405,33 +432,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 }); From 0af274a1f9b9a9cab56351662f8846be44a1ad2f Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 21 Nov 2014 18:09:36 +0100 Subject: [PATCH 03/42] use class hierarchy for preflight-checking --- .../src/com/ibm/wala/dalvik/util/AndroidPreFlightChecks.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidPreFlightChecks.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidPreFlightChecks.java index 7f3173a17..025c6837b 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidPreFlightChecks.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidPreFlightChecks.java @@ -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 entrypoits = AndroidEntryPointManager.ENTRIES; for (AndroidEntryPoint ep : entrypoits) { From 0af7f105ecf4ef28d71b5ce03f7a2dd02c56ba7f Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 21 Nov 2014 15:44:31 +0100 Subject: [PATCH 04/42] cache for selectors --- .../src/com/ibm/wala/types/Selector.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/com.ibm.wala.core/src/com/ibm/wala/types/Selector.java b/com.ibm.wala.core/src/com/ibm/wala/types/Selector.java index 2275919cb..febcb0de7 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/types/Selector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/types/Selector.java @@ -10,6 +10,9 @@ *******************************************************************************/ package com.ibm.wala.types; +import java.util.HashMap; +import java.util.Map; + import com.ibm.wala.classLoader.Language; import com.ibm.wala.util.strings.Atom; @@ -24,8 +27,17 @@ public final class Selector { private final Descriptor descriptor; + private final String s; + + private static final Map CACHE = new HashMap(); + public static Selector make(String selectorStr) { - return make(Language.JAVA, selectorStr); + Selector ret = CACHE.get(selectorStr); + if (ret == null) { + ret = make(Language.JAVA, selectorStr); + CACHE.put(selectorStr, ret); + } + return ret; } public static Selector make(Language l, String selectorStr) { @@ -44,6 +56,7 @@ public final class Selector { public Selector(Atom name, Descriptor descriptor) { this.name = name; this.descriptor = descriptor; + this.s = name.toString() + descriptor.toString(); if (name == null) { throw new IllegalArgumentException("null name"); } @@ -70,7 +83,7 @@ public final class Selector { @Override public String toString() { - return name.toString() + descriptor.toString(); + return s; } public Descriptor getDescriptor() { From 9e5be481389e722c5f2c4582ae2efca65dd51bc3 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Thu, 27 Nov 2014 18:28:06 +0100 Subject: [PATCH 05/42] only generate return statement if caller and callee are compatible --- .../ibm/wala/util/ssa/TypeSafeInstructionFactory.java | 2 +- .../dalvik/ipa/callgraph/androidModel/AndroidModel.java | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/com.ibm.wala.core/src/com/ibm/wala/util/ssa/TypeSafeInstructionFactory.java b/com.ibm.wala.core/src/com/ibm/wala/util/ssa/TypeSafeInstructionFactory.java index 07f88089a..b0c8eea42 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/util/ssa/TypeSafeInstructionFactory.java +++ b/com.ibm.wala.core/src/com/ibm/wala/util/ssa/TypeSafeInstructionFactory.java @@ -612,7 +612,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) { diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModel.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModel.java index ec0bd45fb..582fb5dab 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModel.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModel.java @@ -736,10 +736,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) { From b03cd18adaf57cce3e997d2f44fb7e760543c49c Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Thu, 27 Nov 2014 16:53:34 +0100 Subject: [PATCH 06/42] handle case when exclusions are null --- .../parameters/FlatInstantiator.java | 57 ++++++++--------- .../androidModel/parameters/Instantiator.java | 61 +++++++++---------- .../dalvik/util/AndroidEntryPointLocator.java | 9 ++- 3 files changed, 60 insertions(+), 67 deletions(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/FlatInstantiator.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/FlatInstantiator.java index 295275c3e..00ebcccf6 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/FlatInstantiator.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/FlatInstantiator.java @@ -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 @@ -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 */ 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(); } @@ -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 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 subInstances = new HashSet(); 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 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 getTypes(final TypeReference T, final Set seen) { + logger.debug("getTypes({}, {})", T, seen); final Set ret = new HashSet(); 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; diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/Instantiator.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/Instantiator.java index 6bb79f440..3a2ed49c7 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/Instantiator.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/parameters/Instantiator.java @@ -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 @@ -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 */ 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,7 +124,7 @@ 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(); } @@ -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 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 subInstances = new HashSet(); 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 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 getTypes(final TypeReference T, final Set seen) { + logger.debug("getTypes({}, {})", T, seen); final Set ret = new HashSet(); 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; diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidEntryPointLocator.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidEntryPointLocator.java index fb7944f6f..1f8420654 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidEntryPointLocator.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidEntryPointLocator.java @@ -389,9 +389,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); + } } /** From 1f105dc101824ed7cba490f8a602637d3afd4ab6 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Tue, 27 Jan 2015 14:27:47 +0100 Subject: [PATCH 07/42] staticalize a method --- .../wala/ipa/callgraph/propagation/cfa/ZeroXInstanceKeys.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ZeroXInstanceKeys.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ZeroXInstanceKeys.java index ef2c398c8..ecde34427 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ZeroXInstanceKeys.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ZeroXInstanceKeys.java @@ -319,12 +319,14 @@ public class ZeroXInstanceKeys implements InstanceKeyFactory { return c.getClassHierarchy().isSubclassOf(c, c.getClassHierarchy().lookupClass(TypeReference.JavaLangThrowable)); } - public boolean isStackTraceElement(IClass c) { + /** BEGIN Custom Change: make this method static (like isThrowable) */ + public static boolean isStackTraceElement(IClass c) { if (c == null) { throw new IllegalArgumentException("C is null"); } return c.getReference().equals(TypeReference.JavaLangStackTraceElement); } + /** END Custom Change: make this method static (like isThrowable) */ private boolean allFieldsArePrimitive(IClass c) { if (c.isArrayClass()) { From 7e3fb18fc0d5e6894cded0519164b1270d9cdd68 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Tue, 27 Jan 2015 14:28:08 +0100 Subject: [PATCH 08/42] BUGFIX: when reusing ssa value numbers, consider the case that an instruction may not have a def --- .../src/com/ibm/wala/dalvik/ssa/DexSSABuilder.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ssa/DexSSABuilder.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ssa/DexSSABuilder.java index d82a87ef6..bd9a692fa 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ssa/DexSSABuilder.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ssa/DexSSABuilder.java @@ -389,14 +389,15 @@ 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. */ + /** BEGIN custom change: Bugfix for the case that the instruction does not have a def */ private int reuseOrCreateDef() { - if (getCurrentInstruction() == null) { + if (getCurrentInstruction() == null || !getCurrentInstruction().hasDef()) { return symbolTable.newSymbol(); } else { return getCurrentInstruction().getDef(); } } - + /** END custom change: Bugfix for the case that the instruction does not have a def */ /** * If we've already created the current instruction, return the value number representing the exception the instruction may * throw. Else, create a new symbol From 1acbf4b9f77661540b1cf3699a6df9a3fe38bdbe Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 28 Nov 2014 16:18:32 +0100 Subject: [PATCH 09/42] preserve holes in instruction array when transcribing method summary otherwise the iindex fields in the ssa instructions are inconsistent with their index in the instruction array --- .../src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java | 1 + 1 file changed, 1 insertion(+) diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java index 0d6944ce4..a3a2473fe 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java @@ -295,6 +295,7 @@ public class VolatileMethodSummary { if ((inst == null) || (inst == RESERVED)) { if (DEBUG) { System.err.printf("No instruction at iindex {}", i); } + this.summary.addStatement(null); } else { if (DEBUG) { System.err.printf("Adding @{}: ", inst); } this.summary.addStatement(inst); From 8610ac29c792d44815833ca5ec76fde64a9c4b0b Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Sat, 20 Dec 2014 18:04:51 +0100 Subject: [PATCH 10/42] allow to retrieve Android Model Class with different cha --- .../androidModel/AndroidModelClass.java | 47 +++++++------------ 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModelClass.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModelClass.java index fcb5748ab..b397c6f0a 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModelClass.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModelClass.java @@ -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 @@ -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); From a5b649095122c658af6ad7df1da049874459dd6c Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Sat, 20 Dec 2014 19:15:22 +0100 Subject: [PATCH 11/42] fix getNextProgramCounter() handle the case that the current program counter is free --- .../ibm/wala/ipa/summaries/VolatileMethodSummary.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java index a3a2473fe..75ae752a3 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java @@ -83,7 +83,7 @@ import com.ibm.wala.util.strings.Atom; */ public class VolatileMethodSummary { - private static final boolean DEBUG = false; + private static final boolean DEBUG = true; private boolean allowReservedPC = false; private MethodSummary summary; private List instructions = new ArrayList(); @@ -435,10 +435,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; } /** From b5092637c8b4d8473bfed09cec63eaa73c296335 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Tue, 27 Jan 2015 18:54:11 +0100 Subject: [PATCH 12/42] improve recognition of intent action --- .../ibm/wala/dalvik/ipa/callgraph/propagation/cfa/Intent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/Intent.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/Intent.java index c123e194f..e26b91ec0 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/Intent.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/Intent.java @@ -311,7 +311,7 @@ public class Intent implements ContextItem, Comparable { // 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))); } /** From 3e4af27112ca17494c47e497daf0a5ca799989c2 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Tue, 27 Jan 2015 18:55:37 +0100 Subject: [PATCH 13/42] allow resetting the AndroidEntryPointManager - this is rudimentary support for running the android front-end *multiple times within the same VM* --- .../dalvik/util/AndroidEntryPointManager.java | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidEntryPointManager.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidEntryPointManager.java index c0b96ab1f..1ae239791 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidEntryPointManager.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidEntryPointManager.java @@ -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 @@ -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 */ 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 ENTRIES = new ArrayList(); /** * 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(); + MANAGER = new AndroidEntryPointManager(); + } public Set getComponents() { if (ENTRIES.isEmpty()) { @@ -242,7 +243,7 @@ public final /* singleton */ class AndroidEntryPointManager implements Serializa return prev; } - private Class 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 ctor = this.abstractAndroidModel.getDeclaredConstructor( + final Constructor 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 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; } } From e1beb6aa90b80e3f3df14e12e72e64e5074bdf92 Mon Sep 17 00:00:00 2001 From: Juergen Graf Date: Wed, 5 Nov 2014 17:07:02 +0100 Subject: [PATCH 14/42] add non-recursive dfs solution to compute backedges for large methods --- .../src/com/ibm/wala/util/graph/Acyclic.java | 65 +++++++++++++++++-- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/com.ibm.wala.util/src/com/ibm/wala/util/graph/Acyclic.java b/com.ibm.wala.util/src/com/ibm/wala/util/graph/Acyclic.java index ab94e706c..f41dff704 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/util/graph/Acyclic.java +++ b/com.ibm.wala.util/src/com/ibm/wala/util/graph/Acyclic.java @@ -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 visited = HashSetFactory.make(); - Set 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 visited = HashSetFactory.make(); + final Set onstack = HashSetFactory.make(); + dfs(result, root, G, visited, onstack); + } else { + dfsNonRecursive(result, root, G); + } + return result; } - + private static void dfs(BasicNaturalRelation result, T root, NumberedGraph G, Set visited, Set onstack) { visited.add(root); onstack.add(root); @@ -74,6 +87,48 @@ public class Acyclic { onstack.remove(root); } + private static void dfsNonRecursive(final BasicNaturalRelation result, final T root, final NumberedGraph G) { + final Stack stack = new Stack(); + final Set stackSet = new HashSet(); + final Stack> stackIt = new Stack>(); + final Set finished = new HashSet(); + stack.push(root); + stackSet.add(root); + stackIt.push(G.getSuccNodes(root)); + + while (!stack.isEmpty()) { + final T current = stack.pop(); + stackSet.remove(current); + final Iterator 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 boolean hasIncomingBackEdges(Path p, NumberedGraph G, T root) { /* * TODO: pull out computeBackEdges, and pass in the backedge relation as a parameter to this call From 9c4c3507c4d99356e331b74ef7c53a9b186c84d4 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 13 Feb 2015 15:35:14 +0100 Subject: [PATCH 15/42] cover corner case of method being null --- .../dalvik/util/AndroidEntryPointLocator.java | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidEntryPointLocator.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidEntryPointLocator.java index 1f8420654..6ac75e513 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidEntryPointLocator.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidEntryPointLocator.java @@ -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 @@ -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 */ 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 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 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 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); } } } From cfa005203a9a67c91f62ce018bfcd1dd4829aec0 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 13 Feb 2015 15:35:55 +0100 Subject: [PATCH 16/42] cover corner case of intent or intent's action being null --- .../ibm/wala/dalvik/ipa/callgraph/propagation/cfa/Intent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/Intent.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/Intent.java index e26b91ec0..ab0fc02d7 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/Intent.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/Intent.java @@ -260,7 +260,7 @@ public class Intent implements ContextItem, Comparable { 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)); } /** From b1c10b642f1f6783306b8a238a4483edc1f5d1d1 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 13 Feb 2015 15:41:15 +0100 Subject: [PATCH 17/42] finish all sections only if a section was entered --- .../dalvik/ipa/callgraph/androidModel/AndroidModel.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModel.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModel.java index 582fb5dab..3a2574742 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModel.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/AndroidModel.java @@ -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(); } From 80fd65767565992e935c303097849eb861116910 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 13 Feb 2015 15:59:51 +0100 Subject: [PATCH 18/42] transcribe non-overwritten reserved slots into "goto next" instructions --- .../com/ibm/wala/ipa/summaries/VolatileMethodSummary.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java index 75ae752a3..b69012fff 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java @@ -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,13 +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); From a83ba08980e21dd95b670765a5376f72707f715b Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 13 Feb 2015 16:01:27 +0100 Subject: [PATCH 19/42] turn off debug output --- .../src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java index b69012fff..9b76e5305 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/summaries/VolatileMethodSummary.java @@ -84,7 +84,7 @@ import com.ibm.wala.util.strings.Atom; */ public class VolatileMethodSummary { - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; private boolean allowReservedPC = false; private MethodSummary summary; private List instructions = new ArrayList(); From cfadf0104c66cd2823d6b937063b059266ac5f2d Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 13 Feb 2015 16:18:10 +0100 Subject: [PATCH 20/42] substitute call to deprecated method --- .../structure/LoopAndroidModel.java | 2 +- .../structure/SingleStartAndroidModel.java | 30 ++++++++----------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/LoopAndroidModel.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/LoopAndroidModel.java index 4959895d4..19a5141db 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/LoopAndroidModel.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/LoopAndroidModel.java @@ -101,7 +101,7 @@ public class LoopAndroidModel extends SingleStartAndroidModel { this.outerLoopPC = PC; - PC = makeBrakingNOP(this.outerLoopPC); + PC = body.getNextProgramCounter(); paramManager.scopeDown(true); // Top-Half of Phi-Handling diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/SingleStartAndroidModel.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/SingleStartAndroidModel.java index 99c459ffc..67b1ad012 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/SingleStartAndroidModel.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/SingleStartAndroidModel.java @@ -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 @@ -44,7 +35,9 @@ 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; @@ -73,6 +66,8 @@ import com.ibm.wala.util.ssa.TypeSafeInstructionFactory; * @author Tobias Blaschke */ 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 +93,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 +131,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 forPhi = new ArrayList(2); @@ -152,19 +146,19 @@ public class SingleStartAndroidModel extends AbstractAndroidModel { body.allowReserved(oldAllowReserved); // Close the Loop - - + logger.info("Closing Loop"); + logger.info("PC {}: Goto {}", PC, outerLoopPC); body.addStatement(insts.GotoInstruction(PC, 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 all = paramManager.getAllForPhi(phiKey); - + logger.debug("Into phi {} for {}", all, phiType.getName()); // Narf ... unpacking... paramManager.invalidate(phiKey); From ccb5b02abdf31f43d745c38e28e6d1a999c9fbc4 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 13 Feb 2015 16:18:54 +0100 Subject: [PATCH 21/42] do not add self-loops --- .../androidModel/structure/SingleStartAndroidModel.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/SingleStartAndroidModel.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/SingleStartAndroidModel.java index 67b1ad012..304a80b7a 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/SingleStartAndroidModel.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/SingleStartAndroidModel.java @@ -148,7 +148,9 @@ public class SingleStartAndroidModel extends AbstractAndroidModel { // Close the Loop logger.info("Closing Loop"); logger.info("PC {}: Goto {}", PC, outerLoopPC); - body.addStatement(insts.GotoInstruction(PC, outerLoopPC)); + if (PC != outerLoopPC) { + body.addStatement(insts.GotoInstruction(PC, outerLoopPC)); + } paramManager.scopeUp(); // Add Phi-Statements at the beginning of this block... From 29779f411a8c6e581dc35189e1757f28fa7056a0 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 13 Feb 2015 17:41:00 +0100 Subject: [PATCH 22/42] allow adding a conditional branch instruction --- .../com/ibm/wala/util/ssa/TypeSafeInstructionFactory.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/com.ibm.wala.core/src/com/ibm/wala/util/ssa/TypeSafeInstructionFactory.java b/com.ibm.wala.core/src/com/ibm/wala/util/ssa/TypeSafeInstructionFactory.java index b0c8eea42..def1bf3eb 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/util/ssa/TypeSafeInstructionFactory.java +++ b/com.ibm.wala.core/src/com/ibm/wala/util/ssa/TypeSafeInstructionFactory.java @@ -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; @@ -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]. * From 441cc6f279e13ff745d97e7ce236398ac447cc86 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 13 Feb 2015 17:43:02 +0100 Subject: [PATCH 23/42] bugfix in model: close inner loop using a *conditional* goto This way, the rest of the outer loop (including the jump to the beginning) is also reached in the control-flow which means that the outer loop is modelled as a proper loop --- .../androidModel/structure/SingleStartAndroidModel.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/SingleStartAndroidModel.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/SingleStartAndroidModel.java index 304a80b7a..45c5fe399 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/SingleStartAndroidModel.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/SingleStartAndroidModel.java @@ -42,9 +42,12 @@ 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; @@ -149,7 +152,11 @@ public class SingleStartAndroidModel extends AbstractAndroidModel { logger.info("Closing Loop"); logger.info("PC {}: Goto {}", PC, outerLoopPC); if (PC != outerLoopPC) { - body.addStatement(insts.GotoInstruction(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(); From b378f8c4584c8d8fcd99feeca692ea20ade4fcf8 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 13 Feb 2015 18:40:22 +0100 Subject: [PATCH 24/42] custom change: include target in string representation of cond-branch --- .../com/ibm/wala/ssa/SSAConditionalBranchInstruction.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/com.ibm.wala.core/src/com/ibm/wala/ssa/SSAConditionalBranchInstruction.java b/com.ibm.wala.core/src/com/ibm/wala/ssa/SSAConditionalBranchInstruction.java index 814058b5c..a2f757c35 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ssa/SSAConditionalBranchInstruction.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ssa/SSAConditionalBranchInstruction.java @@ -60,11 +60,12 @@ public class SSAConditionalBranchInstruction extends SSAInstruction { return operator; } + /** BEGIN custom change: include jump target in string representation */ @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); } - + /** END custom change: include jump target in string representation */ /** * @see com.ibm.wala.ssa.SSAInstruction#visit(IVisitor) * @throws IllegalArgumentException if v is null From 4bc25d3ddf1156b4a99b571d120aeca996469958 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 13 Feb 2015 18:41:12 +0100 Subject: [PATCH 25/42] also model outer loops as indefinite instead of infinite --- .../structure/LoopAndroidModel.java | 38 ++++++++++--------- .../structure/LoopKillAndroidModel.java | 36 +++++++++--------- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/LoopAndroidModel.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/LoopAndroidModel.java index 19a5141db..15677f15a 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/LoopAndroidModel.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/LoopAndroidModel.java @@ -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 @@ -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 */ 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,7 +96,7 @@ 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 = body.getNextProgramCounter(); @@ -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 forPhi = new ArrayList(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 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; } diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/LoopKillAndroidModel.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/LoopKillAndroidModel.java index 1ba0a731f..50d41e44b 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/LoopKillAndroidModel.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/LoopKillAndroidModel.java @@ -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 @@ -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 */ 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,7 +90,7 @@ 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); @@ -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 forPhi = new ArrayList(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 all = paramManager.getAllForPhi(phiKey); - + logger.debug("Into phi {} for {}", all, phiType.getName()); // Narf ... unpacking... paramManager.invalidate(phiKey); From a56eeae51a9f739524864eee5c06671efb590614 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 13 Feb 2015 19:35:58 +0100 Subject: [PATCH 26/42] kill deprecated method together with the last call of it --- .../structure/AbstractAndroidModel.java | 52 +++++-------------- .../structure/LoopKillAndroidModel.java | 2 +- 2 files changed, 15 insertions(+), 39 deletions(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/AbstractAndroidModel.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/AbstractAndroidModel.java index 776f403d5..93132ab08 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/AbstractAndroidModel.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/AbstractAndroidModel.java @@ -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 @@ -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. - *

- * 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; } diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/LoopKillAndroidModel.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/LoopKillAndroidModel.java index 50d41e44b..3ce2c1c72 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/LoopKillAndroidModel.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/androidModel/structure/LoopKillAndroidModel.java @@ -93,7 +93,7 @@ public class LoopKillAndroidModel extends LoopAndroidModel { 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 From 8ac515a4527eacd320d73debed9e23d7ac03249c Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 10 Apr 2015 12:50:06 +0200 Subject: [PATCH 27/42] fix download location of apache commons io lib --- com.ibm.wala.cast/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.ibm.wala.cast/build.xml b/com.ibm.wala.cast/build.xml index 027fce457..bf79ce9bd 100644 --- a/com.ibm.wala.cast/build.xml +++ b/com.ibm.wala.cast/build.xml @@ -59,7 +59,7 @@ - + From b66903c8de878594cd13ea6ebde91c954627b6c9 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 10 Apr 2015 12:51:24 +0200 Subject: [PATCH 28/42] ignore lib folder of com.ibm.wala.cast project --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0b7f9415b..3ba2867ee 100644 --- a/.gitignore +++ b/.gitignore @@ -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/ From f2a4bba83f4540b64827a6dd406f8ed9bb16b367 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Fri, 10 Apr 2015 16:17:09 +0200 Subject: [PATCH 29/42] bugfix in debug output: only take item from worklist if it is not empty --- .../ipa/callgraph/propagation/PropagationSystem.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationSystem.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationSystem.java index 8ba89ccce..b2c75f57f 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationSystem.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/PropagationSystem.java @@ -634,10 +634,12 @@ public class PropagationSystem extends DefaultFixedPointSolver Date: Mon, 20 Apr 2015 14:23:05 +0200 Subject: [PATCH 30/42] support multiple intent actions and urls in manifest parser --- .../dalvik/util/AndroidManifestXMLReader.java | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidManifestXMLReader.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidManifestXMLReader.java index b962bc7e3..21b7c25cc 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidManifestXMLReader.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/util/AndroidManifestXMLReader.java @@ -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 allowedTags = EnumSet.copyOf(self.getAllowedSubTags()); - String url = null; - String name = null; - + Set urls = new HashSet(); + Set names = new HashSet(); 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); } From bd96807d7cdf150d95843b62cbd49af9cc9ade0c Mon Sep 17 00:00:00 2001 From: Juergen Graf Date: Thu, 30 Apr 2015 16:24:52 +0200 Subject: [PATCH 31/42] fix bug: npe on control dep computation when exceptions are ignored --- com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/PDG.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/PDG.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/PDG.java index 4eec8fa53..e6e9b068f 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/PDG.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/slicer/PDG.java @@ -238,7 +238,7 @@ public class PDG implements NumberedGraph { // were // exceptional, simply return because at this point there are no nodes. // Otherwise, later this may raise an Exception. - if (controlFlowGraph.getNumberOfNodes() == 0) { + if (controlFlowGraph.getNumberOfNodes() == 0 || controlFlowGraph.getSuccNodeCount(controlFlowGraph.entry()) == 0) { return; } } else { From f4cef8db7a035024ed4e5e4dc0eb50a7b1caddf6 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Wed, 10 Jun 2015 14:15:15 +0200 Subject: [PATCH 32/42] dalvik frontend: set target for SSAGotoInstructions --- .../src/com/ibm/wala/dalvik/ssa/DexSSABuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ssa/DexSSABuilder.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ssa/DexSSABuilder.java index bd9a692fa..529bc73dc 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ssa/DexSSABuilder.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ssa/DexSSABuilder.java @@ -767,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)); } /** From 0583450884f3cb1b9cf19f5cd8f8d12411180002 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Sun, 14 Jun 2015 17:05:25 -0700 Subject: [PATCH 33/42] fix whitespace --- .../cfa/IntentContextSelector.java | 65 +++++++++++-------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/IntentContextSelector.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/IntentContextSelector.java index a83c52ef9..3f621b720 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/IntentContextSelector.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ipa/callgraph/propagation/cfa/IntentContextSelector.java @@ -1,3 +1,12 @@ +/* + * 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 @@ -83,7 +92,7 @@ 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 @@ -115,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 @@ -136,7 +145,7 @@ 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 { @@ -146,12 +155,12 @@ public class IntentContextSelector implements ContextSelector { 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()); @@ -174,7 +183,7 @@ public class IntentContextSelector implements ContextSelector { 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); } @@ -192,7 +201,7 @@ public class IntentContextSelector implements ContextSelector { return Intent.IntentType.SYSTEM_SERVICE; } // TODO override equals and hashCode? - }; + }; } else { intent = null; if (param == null) { @@ -202,10 +211,10 @@ public class IntentContextSelector implements ContextSelector { } } } - + // 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); @@ -222,16 +231,16 @@ 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("(Ljava/lang/String;)V"))) { logger.debug("Handling Intent(String action)"); - actionKey = actualParameters[1]; + actionKey = actualParameters[1]; } else if (calleeSel.equals(Selector.make("(Landroid/content/Intent;)V"))) { logger.debug("Handling Intent(Intent other)"); @@ -253,7 +262,7 @@ public class IntentContextSelector implements ContextSelector { if (calleeSel.equals(Selector.make("(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("(Landroid/content/Context;Ljava/lang/Class;)V"))) { logger.debug("Handling Intent(Context, Class)"); @@ -303,7 +312,7 @@ public class IntentContextSelector implements ContextSelector { 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]; @@ -322,10 +331,10 @@ public class IntentContextSelector implements ContextSelector { 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]; @@ -348,8 +357,8 @@ public class IntentContextSelector implements ContextSelector { 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)) { @@ -364,12 +373,12 @@ public class IntentContextSelector implements ContextSelector { } 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)); @@ -386,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} */ @@ -410,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(); @@ -446,7 +455,7 @@ public class IntentContextSelector implements ContextSelector { } } else if (site.isSpecial() && target.getDeclaringClass().getName().equals( AndroidTypes.IntentSenderName)) { - + logger.warn("Encountered an IntentSender-Object: {}", target); if (target.getNumberOfParameters() == 0) { // public IntentSender() @@ -454,7 +463,7 @@ public class IntentContextSelector implements ContextSelector { } else { // public IntentSender(IIntentSender target) // public IntentSender(IBinder target) - return IntSetUtil.make(new int[] { 0, 1 }); + return IntSetUtil.make(new int[] { 0, 1 }); } } /*else if (site.isSpecial() && target.getDeclaringClass().getName().equals( AndroidTypes.ContextWrapperName)) { From 0d06d7caff310a34580cde5ead27448e3e6aa6d8 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Thu, 18 Jun 2015 18:42:33 +0200 Subject: [PATCH 34/42] com.ibm.wala.dalvik.test: get cup example file more reliably --- com.ibm.wala.dalvik.test/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.ibm.wala.dalvik.test/build.xml b/com.ibm.wala.dalvik.test/build.xml index d66e3fa6d..d08d5bde3 100644 --- a/com.ibm.wala.dalvik.test/build.xml +++ b/com.ibm.wala.dalvik.test/build.xml @@ -44,7 +44,7 @@ - + From b727348af41c414211b86ec68f9d6a648f8d3ced Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Mon, 22 Jun 2015 14:20:57 +0200 Subject: [PATCH 35/42] fix plugin build path for dalvik project --- com.ibm.wala.dalvik/META-INF/MANIFEST.MF | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/com.ibm.wala.dalvik/META-INF/MANIFEST.MF b/com.ibm.wala.dalvik/META-INF/MANIFEST.MF index b57ef0242..cf2821ff8 100644 --- a/com.ibm.wala.dalvik/META-INF/MANIFEST.MF +++ b/com.ibm.wala.dalvik/META-INF/MANIFEST.MF @@ -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 + From 53852ef2a3d62f502324ea50d9be4ea72f3a52dd Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Mon, 22 Jun 2015 15:54:00 +0200 Subject: [PATCH 36/42] fix dalvik eclipse project build path --- com.ibm.wala.dalvik/.classpath | 3 +++ 1 file changed, 3 insertions(+) diff --git a/com.ibm.wala.dalvik/.classpath b/com.ibm.wala.dalvik/.classpath index 853d9a9b9..4c614a90e 100644 --- a/com.ibm.wala.dalvik/.classpath +++ b/com.ibm.wala.dalvik/.classpath @@ -7,5 +7,8 @@ + + + From 620dd15d009fc967ab617b1cd94f583392b40e2b Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Thu, 25 Jun 2015 08:59:21 +0200 Subject: [PATCH 37/42] allow comments in exclusion files --- .../src/com/ibm/wala/util/config/FileOfClasses.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/com.ibm.wala.util/src/com/ibm/wala/util/config/FileOfClasses.java b/com.ibm.wala.util/src/com/ibm/wala/util/config/FileOfClasses.java index 91f7fe4ef..cb6b249af 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/util/config/FileOfClasses.java +++ b/com.ibm.wala.util/src/com/ibm/wala/util/config/FileOfClasses.java @@ -43,6 +43,9 @@ public class FileOfClasses extends SetOfClasses implements Serializable { StringBuffer regex = null; String line; while ((line = is.readLine()) != null) { + /** BEGIN Custom Change: allow comment lines in exclusion files */ + if (line.startsWith("#")) continue; + /** END Custom Change: allow comment lines in exclusion files */ if (regex == null) { regex = new StringBuffer("(" + line + ")"); } else { From 0b92907149e20dcd014bb4889b6afddf82d864ef Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Thu, 25 Jun 2015 09:08:13 +0200 Subject: [PATCH 38/42] Revert "cache for selectors" This reverts commit 0af7f105ecf4ef28d71b5ce03f7a2dd02c56ba7f. --- .../src/com/ibm/wala/types/Selector.java | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/com.ibm.wala.core/src/com/ibm/wala/types/Selector.java b/com.ibm.wala.core/src/com/ibm/wala/types/Selector.java index febcb0de7..2275919cb 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/types/Selector.java +++ b/com.ibm.wala.core/src/com/ibm/wala/types/Selector.java @@ -10,9 +10,6 @@ *******************************************************************************/ package com.ibm.wala.types; -import java.util.HashMap; -import java.util.Map; - import com.ibm.wala.classLoader.Language; import com.ibm.wala.util.strings.Atom; @@ -27,17 +24,8 @@ public final class Selector { private final Descriptor descriptor; - private final String s; - - private static final Map CACHE = new HashMap(); - public static Selector make(String selectorStr) { - Selector ret = CACHE.get(selectorStr); - if (ret == null) { - ret = make(Language.JAVA, selectorStr); - CACHE.put(selectorStr, ret); - } - return ret; + return make(Language.JAVA, selectorStr); } public static Selector make(Language l, String selectorStr) { @@ -56,7 +44,6 @@ public final class Selector { public Selector(Atom name, Descriptor descriptor) { this.name = name; this.descriptor = descriptor; - this.s = name.toString() + descriptor.toString(); if (name == null) { throw new IllegalArgumentException("null name"); } @@ -83,7 +70,7 @@ public final class Selector { @Override public String toString() { - return s; + return name.toString() + descriptor.toString(); } public Descriptor getDescriptor() { From 8d143dbf207886b7b756dfb0a0f332a59aef79ac Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Thu, 25 Jun 2015 09:05:49 +0200 Subject: [PATCH 39/42] remove 'Custom Change' markers --- .../wala/ipa/callgraph/propagation/cfa/ZeroXInstanceKeys.java | 4 ++-- .../src/com/ibm/wala/ssa/SSAConditionalBranchInstruction.java | 4 ++-- .../src/com/ibm/wala/dalvik/ssa/DexSSABuilder.java | 4 ++-- .../src/com/ibm/wala/util/config/FileOfClasses.java | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ZeroXInstanceKeys.java b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ZeroXInstanceKeys.java index ecde34427..24b41b205 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ZeroXInstanceKeys.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ipa/callgraph/propagation/cfa/ZeroXInstanceKeys.java @@ -319,14 +319,14 @@ public class ZeroXInstanceKeys implements InstanceKeyFactory { return c.getClassHierarchy().isSubclassOf(c, c.getClassHierarchy().lookupClass(TypeReference.JavaLangThrowable)); } - /** BEGIN Custom Change: make this method static (like isThrowable) */ + public static boolean isStackTraceElement(IClass c) { if (c == null) { throw new IllegalArgumentException("C is null"); } return c.getReference().equals(TypeReference.JavaLangStackTraceElement); } - /** END Custom Change: make this method static (like isThrowable) */ + private boolean allFieldsArePrimitive(IClass c) { if (c.isArrayClass()) { diff --git a/com.ibm.wala.core/src/com/ibm/wala/ssa/SSAConditionalBranchInstruction.java b/com.ibm.wala.core/src/com/ibm/wala/ssa/SSAConditionalBranchInstruction.java index a2f757c35..933b133cb 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/ssa/SSAConditionalBranchInstruction.java +++ b/com.ibm.wala.core/src/com/ibm/wala/ssa/SSAConditionalBranchInstruction.java @@ -60,12 +60,12 @@ public class SSAConditionalBranchInstruction extends SSAInstruction { return operator; } - /** BEGIN custom change: include jump target in string representation */ + @Override public String toString(SymbolTable symbolTable) { return "conditional branch(" + operator + ", to iindex=" + target + ") " + getValueString(symbolTable, val1) + "," + getValueString(symbolTable, val2); } - /** END custom change: include jump target in string representation */ + /** * @see com.ibm.wala.ssa.SSAInstruction#visit(IVisitor) * @throws IllegalArgumentException if v is null diff --git a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ssa/DexSSABuilder.java b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ssa/DexSSABuilder.java index 529bc73dc..954cf73ae 100644 --- a/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ssa/DexSSABuilder.java +++ b/com.ibm.wala.dalvik/src/com/ibm/wala/dalvik/ssa/DexSSABuilder.java @@ -389,7 +389,7 @@ 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. */ - /** BEGIN custom change: Bugfix for the case that the instruction does not have a def */ + private int reuseOrCreateDef() { if (getCurrentInstruction() == null || !getCurrentInstruction().hasDef()) { return symbolTable.newSymbol(); @@ -397,7 +397,7 @@ public class DexSSABuilder extends AbstractIntRegisterMachine { return getCurrentInstruction().getDef(); } } - /** END custom change: Bugfix for the case that the instruction does not have a def */ + /** * If we've already created the current instruction, return the value number representing the exception the instruction may * throw. Else, create a new symbol diff --git a/com.ibm.wala.util/src/com/ibm/wala/util/config/FileOfClasses.java b/com.ibm.wala.util/src/com/ibm/wala/util/config/FileOfClasses.java index cb6b249af..1b41971e7 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/util/config/FileOfClasses.java +++ b/com.ibm.wala.util/src/com/ibm/wala/util/config/FileOfClasses.java @@ -43,9 +43,9 @@ public class FileOfClasses extends SetOfClasses implements Serializable { StringBuffer regex = null; String line; while ((line = is.readLine()) != null) { - /** BEGIN Custom Change: allow comment lines in exclusion files */ + if (line.startsWith("#")) continue; - /** END Custom Change: allow comment lines in exclusion files */ + if (regex == null) { regex = new StringBuffer("(" + line + ")"); } else { From 65b9e97ae54e58973194e3bcdbcc612a676da964 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Mon, 27 Jul 2015 14:15:12 +0200 Subject: [PATCH 40/42] refine hasExceptions(): return true if there are *uncaught* exceptions --- .../src/com/ibm/wala/cfg/exc/ExceptionPruningAnalysis.java | 5 +++-- .../wala/cfg/exc/intra/ExplodedCFGNullPointerAnalysis.java | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/ExceptionPruningAnalysis.java b/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/ExceptionPruningAnalysis.java index 290ac49d8..17856b740 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/ExceptionPruningAnalysis.java +++ b/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/ExceptionPruningAnalysis.java @@ -59,9 +59,10 @@ public interface ExceptionPruningAnalysis> { /** * 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(); diff --git a/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/intra/ExplodedCFGNullPointerAnalysis.java b/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/intra/ExplodedCFGNullPointerAnalysis.java index e8c2b976f..277321ff2 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/intra/ExplodedCFGNullPointerAnalysis.java +++ b/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/intra/ExplodedCFGNullPointerAnalysis.java @@ -85,7 +85,7 @@ public class ExplodedCFGNullPointerAnalysis implements ExceptionPruningAnalysis< for (IExplodedBasicBlock bb : cfg) { if (bb.getInstruction() == null) continue; List succ = cfg.getExceptionalSuccessors(bb); - if (succ != null && !succ.isEmpty()) { + if (succ != null && succ.contains(cfg.exit())) { hasException = true; break; } From 9b8b3238121bbe3edd18c89bd19f7e53003acc89 Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Mon, 27 Jul 2015 18:30:07 +0200 Subject: [PATCH 41/42] make configurable whether we apply an optimized version of hasExceptions() --- .../ibm/wala/cfg/exc/NullPointerAnalysis.java | 17 ++++++++++++++--- .../exc/inter/InterprocNullPointerAnalysis.java | 12 +++++++----- .../intra/ExplodedCFGNullPointerAnalysis.java | 6 ++++-- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/NullPointerAnalysis.java b/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/NullPointerAnalysis.java index c47d68a85..65eadb79d 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/NullPointerAnalysis.java +++ b/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/NullPointerAnalysis.java @@ -58,7 +58,12 @@ public final class NullPointerAnalysis { public static ExceptionPruningAnalysis 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 + createIntraproceduralExplodedCFGAnalysis(TypeReference[] ignoredExceptions, IR ir, ParameterState paramState, MethodState mState, boolean optHasException) { + return new ExplodedCFGNullPointerAnalysis(ignoredExceptions, ir, paramState, mState, optHasException); } public static ExceptionPruningAnalysis @@ -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 + 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(); } - } diff --git a/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/inter/InterprocNullPointerAnalysis.java b/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/inter/InterprocNullPointerAnalysis.java index 4182e6050..489e795f5 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/inter/InterprocNullPointerAnalysis.java +++ b/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/inter/InterprocNullPointerAnalysis.java @@ -64,20 +64,22 @@ public final class InterprocNullPointerAnalysis { private final TypeReference[] ignoredExceptions; private final MethodState defaultMethodState; private final Map 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(); + 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 intra2 = - NullPointerAnalysis.createIntraproceduralExplodedCFGAnalysis(ignoredExceptions, ir, paramState, mState); + NullPointerAnalysis.createIntraproceduralExplodedCFGAnalysis(ignoredExceptions, ir, paramState, mState, optHasExceptions); final int deletedEdges2 = intra2.compute(progress); final ControlFlowGraph 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 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 cfg = intra.getCFG(); diff --git a/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/intra/ExplodedCFGNullPointerAnalysis.java b/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/intra/ExplodedCFGNullPointerAnalysis.java index 277321ff2..963c20695 100644 --- a/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/intra/ExplodedCFGNullPointerAnalysis.java +++ b/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/intra/ExplodedCFGNullPointerAnalysis.java @@ -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 succ = cfg.getExceptionalSuccessors(bb); - if (succ != null && succ.contains(cfg.exit())) { + if (succ != null && !succ.isEmpty() && (!optHasExceptions || succ.contains(cfg.exit()))) { hasException = true; break; } From 5aae6234e8e2e4c9a12881b715ded20ab5e9e6af Mon Sep 17 00:00:00 2001 From: Martin Mohr Date: Thu, 30 Jul 2015 17:19:34 +0200 Subject: [PATCH 42/42] give BasicNullaryStatements a toString() method Before, fixed-point systems containing BasicNullaryStatements caused crashes when trying to output them (because toString() method of AbstractStatement assumes that there is Right-Hand-Side, but BasicNullaryStatements throw an UnsupportedOperationException when trying to get them). Why shouldn't BasicNullaryStatements have a string representation? --- .../fixedpoint/impl/BasicNullaryStatement.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/com.ibm.wala.util/src/com/ibm/wala/fixedpoint/impl/BasicNullaryStatement.java b/com.ibm.wala.util/src/com/ibm/wala/fixedpoint/impl/BasicNullaryStatement.java index 3ba5bd047..b3740d93f 100644 --- a/com.ibm.wala.util/src/com/ibm/wala/fixedpoint/impl/BasicNullaryStatement.java +++ b/com.ibm.wala.util/src/com/ibm/wala/fixedpoint/impl/BasicNullaryStatement.java @@ -23,7 +23,7 @@ public class BasicNullaryStatement extends NullaryStatement */ private final NullaryOperator operator; - BasicNullaryStatement(T lhs, NullaryOperator operator) { + public BasicNullaryStatement(T lhs, NullaryOperator operator) { super(lhs); this.operator = operator; } @@ -35,4 +35,20 @@ public class BasicNullaryStatement extends NullaryStatement public NullaryOperator 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; + } }