/******************************************************************************* * Copyright (c) 2012 Andreas Engelbredt Dalsgaard <andreas.dalsgaard@gmail.com>. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html * * Contributors: * Andreas Engelbredt Dalsgaard <andreas.dalsgaard@gmail.com> ******************************************************************************/ package analyser; import java.io.IOException; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import com.ibm.wala.analysis.pointers.BasicHeapGraph; import com.ibm.wala.analysis.pointers.HeapGraph; import com.ibm.wala.analysis.reflection.InstanceKeyWithNode; import com.ibm.wala.analysis.reflection.ReflectionContextInterpreter; import com.ibm.wala.classLoader.ClassLoaderFactory; import com.ibm.wala.classLoader.ClassLoaderFactoryImpl; import com.ibm.wala.classLoader.IClass; import com.ibm.wala.classLoader.IClassLoader; import com.ibm.wala.classLoader.IMethod; import com.ibm.wala.classLoader.Module; import com.ibm.wala.ipa.callgraph.AnalysisCache; import com.ibm.wala.ipa.callgraph.AnalysisOptions; import com.ibm.wala.ipa.callgraph.AnalysisOptions.ReflectionOptions; import com.ibm.wala.ipa.callgraph.AnalysisScope; import com.ibm.wala.ipa.callgraph.CGNode; import com.ibm.wala.ipa.callgraph.CallGraph; import com.ibm.wala.ipa.callgraph.CallGraphBuilder; import com.ibm.wala.ipa.callgraph.Context; import com.ibm.wala.ipa.callgraph.ContextSelector; import com.ibm.wala.ipa.callgraph.Entrypoint; import com.ibm.wala.ipa.callgraph.impl.ClassHierarchyClassTargetSelector; import com.ibm.wala.ipa.callgraph.impl.ClassHierarchyMethodTargetSelector; import com.ibm.wala.ipa.callgraph.impl.DefaultContextSelector; import com.ibm.wala.ipa.callgraph.impl.DelegatingContextSelector; import com.ibm.wala.ipa.callgraph.impl.Util; import com.ibm.wala.ipa.callgraph.propagation.AbstractFieldPointerKey; import com.ibm.wala.ipa.callgraph.propagation.AbstractLocalPointerKey; import com.ibm.wala.ipa.callgraph.propagation.AbstractTypeInNode; import com.ibm.wala.ipa.callgraph.propagation.AllocationSiteInNodeFactory; import com.ibm.wala.ipa.callgraph.propagation.ConcreteTypeKey; import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey; import com.ibm.wala.ipa.callgraph.propagation.InstanceFieldKey; import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey; import com.ibm.wala.ipa.callgraph.propagation.NormalAllocationInNode; import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis; import com.ibm.wala.ipa.callgraph.propagation.PointerKey; import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter; import com.ibm.wala.ipa.callgraph.propagation.SSAPropagationCallGraphBuilder; import com.ibm.wala.ipa.callgraph.propagation.StaticFieldKey; import com.ibm.wala.ipa.callgraph.propagation.cfa.DefaultPointerKeyFactory; import com.ibm.wala.ipa.callgraph.propagation.cfa.DefaultSSAInterpreter; import com.ibm.wala.ipa.callgraph.propagation.cfa.DelegatingSSAContextInterpreter; import com.ibm.wala.ipa.callgraph.propagation.cfa.ExceptionReturnValueKey; import com.ibm.wala.ipa.callgraph.propagation.cfa.ZeroXCFABuilder; import com.ibm.wala.ipa.callgraph.propagation.cfa.ZeroXInstanceKeys; import com.ibm.wala.ipa.cha.ClassHierarchy; import com.ibm.wala.ipa.cha.IClassHierarchy; import com.ibm.wala.ipa.summaries.BypassClassTargetSelector; import com.ibm.wala.shrikeCT.InvalidClassFileException; import com.ibm.wala.util.CancelException; import com.ibm.wala.util.WalaException; import com.ibm.wala.util.io.CommandLine; public class ScjMemoryScopeAnalysis { public static Boolean analyseWithoutJRE = false; public static void main(String[] args) throws WalaException { String primordial, main; Properties p = CommandLine.parse(args); int problemCounter = 0; boolean appAlone = false; if (p.getProperty("application") == null ) util.print_usage(); if (p.getProperty("main") != null) main = p.getProperty("main"); else main = "Main"; if (p.getProperty("primordial") != null) primordial = p.getProperty("primordial"); else primordial = null; if (p.getProperty("appAlone") != null) { if (p.getProperty("primordial") != null) util.print_usage(); String appAloneStr = p.getProperty("appAlone"); if (appAloneStr.equals("true") || appAloneStr.equals("True") || appAloneStr.equals("1")) appAlone = true; } try { Set<Problem> problems = buildPointsTo(p.getProperty("application"), main, primordial, appAlone); Iterator<Problem> pItr = problems.iterator(); System.out.print("Problems:\n"); while ( pItr.hasNext() ) { String strNext = pItr.next().toString(); if (!strNext.isEmpty()) { System.out.print(strNext+"\n"); problemCounter++; } } System.out.print("Nr. of problems: "+problemCounter+"\n"); } catch (Exception e) { e.printStackTrace(); } } public static Set<Problem> buildPointsTo(String application, String main_class, String primordial, boolean appAlone) throws WalaException, IllegalArgumentException, CancelException, IOException, InvalidClassFileException { analyseWithoutJRE = appAlone; return buildPointsTo(application, main_class, primordial); } public static Set<Problem> buildPointsTo(String application, String main_class, String primordial) throws WalaException, IllegalArgumentException, CancelException, IOException, InvalidClassFileException { AnalysisScope scope = MyAnalysisScopeReader.makeJavaBinaryAnalysisScope(application, primordial, null); ClassHierarchy cha = ClassHierarchy.make(scope); Iterable<Entrypoint> entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, "L"+main_class); AnalysisOptions options = new AnalysisOptions(scope, entrypoints); options.setReflectionOptions(ReflectionOptions.NONE); ContextSelector scjContextSelector = new ScjContextSelector(cha); com.ibm.wala.ipa.callgraph.CallGraphBuilder builder = ZeroXCFABuilder(options, new AnalysisCache(), cha, scope, scjContextSelector); CallGraph cg = builder.makeCallGraph(options,null); PointerAnalysis pointerAnalysis = builder.getPointerAnalysis(); BasicHeapGraph bhg = new BasicHeapGraph(pointerAnalysis, cg); HashSet<Problem> problems = new HashSet<Problem>(); HashSet<MemoryAnnotation> annotations = new HashSet<MemoryAnnotation>(); runAnalysis(bhg.getPointerAnalysis(), (HeapGraph)bhg, problems, annotations); /* Generate annotations */ System.out.print("Annotations:\n"); //RunsIn Annotations Iterator<Entry<IMethod, ScjScopeStack>> pItr = ((ScjContextSelector)scjContextSelector).methodScopeMap.entrySet().iterator(); while ( pItr.hasNext() ) { Entry<IMethod, ScjScopeStack> entry = pItr.next(); String className = entry.getKey().getDeclaringClass().getName().toString(); if( entry.getValue().size() == 1) annotations.add(new MemoryAnnotationRunsIn(entry.getValue().getLast(), entry.getKey())); else annotations.add(new MemoryAnnotationRunsIn(null, entry.getKey(), entry.getValue())); } Iterator<Entry<IClass, ScjScopeStack>> pItr2 = ((ScjContextSelector)scjContextSelector).classScopeMap.entrySet().iterator(); //Scope - Class Annotations while ( pItr2.hasNext() ) { Entry<IClass, ScjScopeStack> entry = pItr2.next(); annotations.add(new MemoryAnnotationScope(entry.getValue().getLast(),entry.getKey(),null)); } //DefineScope Annotations Iterator<ScjScopeStack> pItr3 = ((ScjContextSelector)scjContextSelector).scopeStacks.iterator(); while ( pItr3.hasNext() ) { ScjScopeStack ss = pItr3.next(); annotations.add(new MemoryAnnotationDefineScope(ss)); } //Print Annotations MemoryAnnotation meman; String className; for (java.util.Iterator<MemoryAnnotation> i = annotations.iterator(); i.hasNext(); ) { meman = i.next(); className = meman.getClassName(); if ( !className.startsWith("Ljava") && !className.startsWith("Lcom") && !className.startsWith("Ljoprt") ) { System.out.print(meman.toString()); } } return problems; } public static void runAnalysis(PointerAnalysis pa, HeapGraph hg, HashSet<Problem> problems, HashSet<MemoryAnnotation> annotations) { Iterator<InstanceKey> ikItr = pa.getInstanceKeys().iterator(); int i = 0; while( ikItr.hasNext() ) { InstanceKey ik = ikItr.next(); Iterator<Object> pkIter = hg.getPredNodes(ik); if (getScjContext(ik) == null) { i++; } else { while (pkIter.hasNext()) { Object pk = pkIter.next(); if (!getScjContext(ik).less(getScjContext(pk))) report_problems(problems, ik, pk); } } } if (i > 10) util.error("Unexpected number: "+i+" of InstanceKey objects with context == Null"); //Scope - Field Annotations Iterator<PointerKey> pointKIter = pa.getPointerKeys().iterator(); ikItr = pa.getInstanceKeys().iterator(); ScjContext context; PointerKey pk; while (pointKIter.hasNext()) { pk = pointKIter.next(); context = getScjContext(pk); if (context != null) { if (pk instanceof InstanceFieldKey) { InstanceFieldKey ifk = (InstanceFieldKey) pk; annotations.add(new MemoryAnnotationScope(context.getStackTop(), ifk.getField().getDeclaringClass(), ifk.getField().getName().toString())); } } } } private static void report_problems(HashSet<Problem> problems, InstanceKey ik, Object pk) { if (ik instanceof InstanceKeyWithNode) { InstanceKeyWithNode ikn = (InstanceKeyWithNode) ik; if (pk instanceof InstanceFieldKey){ problems.add(new ProblemField(ikn, (InstanceFieldKey)pk)); } else if (pk instanceof StaticFieldKey) { problems.add(new ProblemStaticField(ikn, (StaticFieldKey)pk)); } else if (pk instanceof ExceptionReturnValueKey) { //XXX: We currently do not handle exceptions util.warnException(); } else if (pk instanceof AbstractLocalPointerKey) { problems.add(new ProblemPkIk(ikn, (AbstractLocalPointerKey)pk)); } else{ if (pk instanceof FilteredPointerKey) { problems.add(new ProblemUnknown("Filtered mismatch is node: "+ pk.getClass() + "scopes: "+getScjContext(pk)+ " result: " + getScjContext(ik)+ "\n instance of class: "+ikn.getNode().getMethod().getDeclaringClass() + " in method: " + ikn.getNode().getMethod().getName()+ "\n")); } else { problems.add(new ProblemUnknown("Unknown mismatch is node: "+ pk.getClass() + "scopes: "+getScjContext(pk)+ " result: " + getScjContext(ik)+ "\n instance of class: "+ikn.getNode().getMethod().getDeclaringClass() + " in method: " + ikn.getNode().getMethod().getName()+ "\n")); } } } else { problems.add(new ProblemUnknown("Unknown mismatch is: "+ pk.getClass() + "scopes: "+getScjContext(pk)+ " result: " + getScjContext(ik)+"\n")); } } private static ScjContext getScjContext(Object o) { Context context = null; if(o instanceof AbstractTypeInNode) { // In case o is an instancekey this is context = ((AbstractTypeInNode) o).getNode().getContext(); } else if(o instanceof AbstractLocalPointerKey) { context = ((AbstractLocalPointerKey) o).getNode().getContext(); } else if (o instanceof AbstractFieldPointerKey) { context = getScjContext(((AbstractFieldPointerKey) o).getInstanceKey()); } else if (o instanceof StaticFieldKey) { context = new ScjContext(null, "Ljavax/realtime/ImmortalMemory", ScjScopeType.IMMORTAL); } if (context instanceof ScjContext) return (ScjContext) context; return null; } private static CallGraphBuilder ZeroXCFABuilder(AnalysisOptions options, AnalysisCache cache, ClassHierarchy cha, AnalysisScope scope, ContextSelector customSelector) { if (options == null) { throw new IllegalArgumentException("options is null"); } Util.addDefaultSelectors(options, cha); Util.addDefaultBypassLogic(options, scope, Util.class.getClassLoader(), cha); return new ZeroXCFABuilder(cha, options, cache, customSelector, null, ZeroXInstanceKeys.ALLOCATIONS | ZeroXInstanceKeys.SMUSH_MANY ); } }