diff --git a/.gitignore b/.gitignore index 93fff4ccf..f68a0a678 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ .idea/ stava.iml .DS_Store + +out diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..dda89494c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "Launch Current File", + "request": "launch", + "mainClass": "${file}" + }, + { + "type": "java", + "name": "Launch Main", + "request": "launch", + "mainClass": "Main", + "projectName": "stava_862dc55b" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..0b75109cc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "java.project.referencedLibraries": [ + "lib/**/*.jar", + "soot/sootclasses-trunk-jar-with-dependencies.jar" + ] +} \ No newline at end of file diff --git a/scripts/run.sh b/scripts/run.sh index 318dd0e82..32f771271 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -3,8 +3,14 @@ # Sample script to be used to run the project on non-benchmark code. # Set the paths according to your installation. All paths must be full paths. # Instructions: ./run.sh ClassName + +if [ -z "$1" ]; then + echo "No TestCase Number Provided"; + exit +fi + # Installed path of Java 8 JDK -java_install_path="/usr/lib/jvm/java-8-oracle/" +java_install_path="/usr/lib/jvm/java-8-openjdk-amd64/" # The soot jar to be used. soot_path=`realpath ../soot/sootclasses-trunk-jar-with-dependencies.jar` @@ -13,10 +19,10 @@ soot_path=`realpath ../soot/sootclasses-trunk-jar-with-dependencies.jar` stava_path=`realpath ..` # The directory to be analysed. -test_path=`realpath ../tests/test20/` +test_path=`realpath ../tests/test$1/` # The directory inside which stava will output the results. -output_path=`realpath ../out/testcase/` +output_path=`realpath ../out/testcase$1/` java_compiler="${java_install_path}/bin/javac" java_vm="${java_install_path}/bin/java" diff --git a/src/analyser/MethodsLinkingAnalyser.java b/src/analyser/MethodsLinkingAnalyser.java new file mode 100644 index 000000000..d38f938d1 --- /dev/null +++ b/src/analyser/MethodsLinkingAnalyser.java @@ -0,0 +1,211 @@ +package analyser; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +import soot.*; +import main.CHATransform; +import ptg.ObjectNode; +import ptg.ObjectType; +import ptg.PointsToGraph; +import soot.jimple.Constant; +import soot.jimple.InstanceInvokeExpr; +import soot.jimple.InvokeExpr; +import soot.jimple.internal.JInvokeStmt; +import soot.jimple.internal.JStaticInvokeExpr; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; + +public class MethodsLinkingAnalyser extends SceneTransformer { + public static ConcurrentHashMap > nativeLocals = new ConcurrentHashMap<>(); + + public static ArrayList whitelistedNatives = new ArrayList<> ( + Arrays.asList("") + ); + + public static ArrayList blacklistedNatives = new ArrayList<> ( + Arrays.asList("", + "", + "") + ); + + + private Set methodsProcessed; + private Set methodsProcessing; + + public MethodsLinkingAnalyser() { + methodsProcessed = new HashSet(); + methodsProcessing = new HashSet(); + } + + @Override + protected void internalTransform(String arg0, Map arg1) { + // Get the call graph, and start processing the methods + CallGraph cg = Scene.v().getCallGraph(); + Iterator callerEdges = cg.sourceMethods(); + + while (callerEdges.hasNext()) { + SootMethod methodCaller = (SootMethod) callerEdges.next(); + // System.out.println("PRIYAM method caller: " + methodCaller); + processMethod(methodCaller); + } + } + + private void processMethod(SootMethod methodCaller) { + if (methodCaller.isJavaLibraryMethod()) { + return; + } + + if (methodsProcessed.contains(methodCaller)) { + // Method already computed + // we have the results ready + return; + } + + if (methodsProcessing.contains(methodCaller)) { + // Recursive loop + // ASK - See what to do + return; + } + + methodsProcessing.add(methodCaller); + + System.out.println("PRIYAM Method Name: "+ methodCaller.getBytecodeSignature() + ":" + methodCaller.getName()); + Body body = methodCaller.getActiveBody(); + PatchingChain units = body.getUnits(); + + for (Unit u : units) { + // System.out.println("PRIYAM unit: " + u); + if (u instanceof JInvokeStmt) { + JInvokeStmt stmt = (JInvokeStmt) u; + InvokeExpr expr = stmt.getInvokeExpr(); + handleExpr(methodCaller, u, expr); + } + } + + methodsProcessing.remove(methodCaller); + methodsProcessed.add(methodCaller); + } + + public void handleExpr( + SootMethod methodCaller, Unit u, InvokeExpr expr) { + PointsToGraph ptg = StaticAnalyser.ptgs.get(methodCaller); + + if (ptg == null) { + // If no points to graph, no need to process further + return; + } + + CallGraph cg = Scene.v().getCallGraph(); + + Iterator iedges = cg.edgesOutOf(u); + List args = expr.getArgs(); + + List edges = new ArrayList<>(); + if (!iedges.hasNext()) { + iedges = CHATransform.getCHA().edgesOutOf(u); + } + + while (iedges.hasNext()) { + edges.add(iedges.next()); + } + + if (edges.size() == 0) { + // System.out.println("Empty edges: " + expr + ", function incoming edges: " + cg.edgesInto(methodCaller).hasNext() + + // " Method: " + methodCaller.getBytecodeSignature()); + edges.add(new Edge(methodCaller, u, expr.getMethod(), Kind.SPECIAL)); + } + + if (expr instanceof InstanceInvokeExpr) { + // ASK - No need to handle instance invoke expr? + } else if (expr instanceof JStaticInvokeExpr) { + } else { + System.err.println("Unidentified invoke expr: " + expr.toString()); + throw new IllegalArgumentException(expr.toString()); + } + + for (Edge edge : edges) { + /* 1. + * We traverse and find the caller callie relationship + * between ObjectNodes + */ + SootMethod method = edge.tgt(); + int paramCount = method.getParameterCount(); + + // Recursion to first process the method + // if not already processed + if (!methodsProcessed.contains(method)) { + processMethod(method); + } + + Map> paramMapping = new HashMap>(); + for (int i = 0; i < paramCount; i++) { + ObjectNode obj = new ObjectNode(i, ObjectType.parameter); + // ConditionalValue cv = new ConditionalValue(method, obj, true); + + if (edge.kind() == Kind.REFL_INVOKE) + paramMapping.put(obj, ptg.vars.get((Local) args.get(1))); + else if (edge.kind() == Kind.REFL_CONSTR_NEWINSTANCE) + paramMapping.put(obj, ptg.vars.get((Local) args.get(0))); + else { + Value arg = args.get(i); + if (arg.getType() instanceof RefType || arg.getType() instanceof ArrayType) + if (!(arg instanceof Constant)) { // Notice the not(!) + // ptg.addParametricEdge((Local) args.get(i), cv); + // System.out.println("args get i: " + args.get(i)); + paramMapping.put(obj, ptg.vars.get((Local) args.get(i))); + } + } + } + + // System.out.println("PRIYAM PARAMS MAPPING: " + paramMapping); + + /* 2. + * Now, loop in the callie method's ptg to find if there + * exists any relationship/node between the params + * If exists, add the realtion for corresponding values in + * paramsMapping also + */ + PointsToGraph calliePTG = StaticAnalyser.ptgs.get(method); + System.out.println("PRIYAM METHOD: " + method); + System.out.println("PRIYAM PTGS: " + StaticAnalyser.ptgs); + System.out.println("PRIYAM calliePTG: " + calliePTG); + // If ptg gives error, ensure StaticAnalysis has been done + + for (int i = 0; i < paramCount; i++) { + ObjectNode obj = new ObjectNode(i, ObjectType.parameter); + Map> pointingTo = calliePTG.fields.get(obj); + + if (pointingTo == null) { + continue; + } + + for (Map.Entry> entry : pointingTo.entrySet()) { + for (ObjectNode fieldObj : entry.getValue()) { + System.out.println("There exists an edge from: " + obj + " to " + fieldObj + " by " + entry.getKey()); + if (fieldObj.type != ObjectType.parameter) { + continue; + } + + if (!paramMapping.containsKey(obj) || !paramMapping.containsKey(fieldObj)) { + // If paramsMapping does not have the object, it can happen if null is passed + continue; + } + + // Find paramsMapping for obj + // Find paramsMapping for fieldObj + // Add an edge from objs to fieldObjs + for (ObjectNode objInCaller : paramMapping.get(obj)) { + for (ObjectNode fieldObjInCaller : paramMapping.get(fieldObj)) { + System.out.println("There should exists an edge from: " + objInCaller + " to " + fieldObjInCaller + " by " + entry.getKey()); + ptg.WEAK_makeField(objInCaller, entry.getKey(), fieldObjInCaller); + } + } + } + } + } + + System.out.println("AFTER PRIYAM PTGS: " + StaticAnalyser.ptgs + "\n"); + } + } +} diff --git a/src/analyser/StackOrderAnalyser.java b/src/analyser/StackOrderAnalyser.java new file mode 100644 index 000000000..521ab426d --- /dev/null +++ b/src/analyser/StackOrderAnalyser.java @@ -0,0 +1,199 @@ +package analyser; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +import soot.*; +import es.ConditionalValue; +import es.EscapeStatus; +import main.CHATransform; +import ptg.ObjectNode; +import ptg.ObjectType; +import ptg.PointsToGraph; +import soot.jimple.Constant; +import soot.jimple.InstanceInvokeExpr; +import soot.jimple.InvokeExpr; +import soot.jimple.internal.JInvokeStmt; +import soot.jimple.internal.JStaticInvokeExpr; +import soot.jimple.toolkits.callgraph.CallGraph; +import soot.jimple.toolkits.callgraph.Edge; + +public class StackOrderAnalyser extends BodyTransformer { + public static ConcurrentHashMap > nativeLocals = new ConcurrentHashMap<>(); + + public static ArrayList whitelistedNatives = new ArrayList<> ( + Arrays.asList("") + ); + + public static ArrayList blacklistedNatives = new ArrayList<> ( + Arrays.asList("", + "", + "") + ); + + + private Set methodsProcessed; + private Set methodsProcessing; + + public StackOrderAnalyser() { + methodsProcessed = new HashSet(); + methodsProcessing = new HashSet(); + } + + @Override + protected void internalTransform(Body body, String phasename, Map options) { + SootMethod method = body.getMethod(); + processMethod(method); + } + + private void processMethod(SootMethod method) { + if (method.isJavaLibraryMethod()) { + return; + } + + if (methodsProcessed.contains(method)) { + // Method already computed + // we have the results ready + return; + } + + if (methodsProcessing.contains(method)) { + // Recursive loop + // ASK - See what to do + return; + } + + methodsProcessing.add(method); + + System.out.println("PRIYAM Method Name: "+ method.getBytecodeSignature() + ":" + method.getName()); + Body body = method.getActiveBody(); + PatchingChain units = body.getUnits(); + + for (Unit u : units) { + // System.out.println("PRIYAM unit: " + u); + if (u instanceof JInvokeStmt) { + JInvokeStmt stmt = (JInvokeStmt) u; + InvokeExpr expr = stmt.getInvokeExpr(); + handleExpr(method, u, expr); + } + } + + methodsProcessing.remove(method); + methodsProcessed.add(method); + } + + public void handleExpr( + SootMethod m, Unit u, InvokeExpr expr) { + PointsToGraph ptg = StaticAnalyser.ptgs.get(m); + CallGraph cg = Scene.v().getCallGraph(); + + Iterator iedges = cg.edgesOutOf(u); + List args = expr.getArgs(); + + List edges = new ArrayList<>(); + if (!iedges.hasNext()) { + iedges = CHATransform.getCHA().edgesOutOf(u); + } + + while (iedges.hasNext()) { + edges.add(iedges.next()); + } + + if (edges.size() == 0) { + // System.out.println("Empty edges: " + expr + ", function incoming edges: " + cg.edgesInto(m).hasNext() + + // " Method: " + m.getBytecodeSignature()); + edges.add(new Edge(m, u, expr.getMethod(), Kind.SPECIAL)); + } + + if (expr instanceof InstanceInvokeExpr) { + // ASK - No need to handle instance invoke expr? + } else if (expr instanceof JStaticInvokeExpr) { + } else { + System.err.println("Unidentified invoke expr: " + expr.toString()); + throw new IllegalArgumentException(expr.toString()); + } + + for (Edge edge : edges) { + /* 1. + * We traverse and find the caller callie relationship + * between ObjectNodes + */ + SootMethod method = edge.tgt(); + int paramCount = method.getParameterCount(); + + // TODO - Add a recursion to first process the method + // if not already processed + if (!methodsProcessed.contains(method)) { + processMethod(method); + } + + Map> paramMapping = new HashMap>(); + for (int i = 0; i < paramCount; i++) { + ObjectNode obj = new ObjectNode(i, ObjectType.parameter); + // ConditionalValue cv = new ConditionalValue(method, obj, true); + + if (edge.kind() == Kind.REFL_INVOKE) + paramMapping.put(obj, ptg.vars.get((Local) args.get(1))); + else if (edge.kind() == Kind.REFL_CONSTR_NEWINSTANCE) + paramMapping.put(obj, ptg.vars.get((Local) args.get(0))); + else { + Value arg = args.get(i); + if (arg.getType() instanceof RefType || arg.getType() instanceof ArrayType) + if (!(arg instanceof Constant)) { // Notice the not(!) + // ptg.addParametricEdge((Local) args.get(i), cv); + paramMapping.put(obj, ptg.vars.get((Local) args.get(i))); + } + } + } + + // System.out.println("PRIYAM PARAMS MAPPING: " + paramMapping); + + /* 2. + * Now, loop in the callie method's ptg to find if there + * exists any relationship/node between the params + * If exists, add the realtion for corresponding values in + * paramsMapping also + */ + PointsToGraph calliePTG = StaticAnalyser.ptgs.get(method); + System.out.println("PRIYAM METHOD: " + method); + System.out.println("PRIYAM PTGS: " + StaticAnalyser.ptgs); + System.out.println("PRIYAM calliePTG: " + calliePTG); + // If ptg gives error, ensure StaticAnalysis has been done + + for (int i = 0; i < paramCount; i++) { + ObjectNode obj = new ObjectNode(i, ObjectType.parameter); + Map> pointingTo = calliePTG.fields.get(obj); + + if (pointingTo == null) { + continue; + } + + for (Map.Entry> entry : pointingTo.entrySet()) { + for (ObjectNode fieldObj : entry.getValue()) { + System.out.println("There exists an edge from: " + obj + " to " + fieldObj + " by " + entry.getKey()); + if (fieldObj.type != ObjectType.parameter) { + continue; + } + + if (!paramMapping.containsKey(obj) || !paramMapping.containsKey(fieldObj)) { + // If paramsMapping does not have the object, it can happen if null is passed + continue; + } + + // Find paramsMapping for obj + // Find paramsMapping for fieldObj + // Add an edge from objs to fieldObjs + for (ObjectNode objInCaller : paramMapping.get(obj)) { + for (ObjectNode fieldObjInCaller : paramMapping.get(fieldObj)) { + System.out.println("There should exists an edge from: " + objInCaller + " to " + fieldObjInCaller + " by " + entry.getKey()); + ptg.WEAK_makeField(objInCaller, entry.getKey(), fieldObjInCaller); + } + } + } + } + } + + System.out.println("AFTER PRIYAM PTGS: " + StaticAnalyser.ptgs + "\n"); + } + } +} diff --git a/src/analyser/StaticAnalyser.java b/src/analyser/StaticAnalyser.java index d07487aea..ef75a911b 100644 --- a/src/analyser/StaticAnalyser.java +++ b/src/analyser/StaticAnalyser.java @@ -19,16 +19,22 @@ import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; +import java.util.Collections; import java.util.regex.*; public class StaticAnalyser extends BodyTransformer { - private boolean allNonEscaping; + private static boolean allNonEscaping; public static Map ptgs; public static Map> summaries; + public static Map> stackOrders; public static LinkedHashMap analysis; public static List noBCIMethods; + + public static Set methodsProcessed; + public static Set methodsProcessing; + String[] ignoreFuncs = { // "", // "", @@ -74,8 +80,12 @@ public StaticAnalyser() { analysis = new LinkedHashMap<>(); ptgs = new ConcurrentHashMap<>(); summaries = new ConcurrentHashMap<>(); + stackOrders = new ConcurrentHashMap<>(); noBCIMethods = new ArrayList<>(); allNonEscaping = false; + + methodsProcessed = Collections.synchronizedSet(new HashSet()); + methodsProcessing = Collections.synchronizedSet(new HashSet()); } private int getSummarySize(HashMap summary) @@ -85,6 +95,10 @@ private int getSummarySize(HashMap summary) @Override protected void internalTransform(Body body, String phasename, Map options) { + processMethod(body); + } + + public static void processMethod(Body body) { // if (body.getMethod().getBytecodeSignature().toString() // .compareTo("") != 0) // { @@ -93,7 +107,26 @@ protected void internalTransform(Body body, String phasename, Map")){ // System.out.println("Skipping this method"); // return; @@ -296,10 +329,15 @@ protected void internalTransform(Body body, String phasename, Map nativeList, Map summary, PointsToGraph ptg) { + private static void markAsEscaping(List nativeList, Map summary, PointsToGraph ptg) { if (nativeList == null) return; for (Local obj: nativeList) { @@ -310,14 +348,14 @@ private void markAsEscaping(List nativeList, Map summary) { + private static void markAsNonEscaping(Map summary) { for (ObjectNode obj: summary.keySet()) { EscapeStatus es = new EscapeStatus(NoEscape.getInstance()); summary.put(obj, es); } } - private void setParamsAsEscaping(SootMethod m, Map summary) { + private static void setParamsAsEscaping(SootMethod m, Map summary) { summary.clear(); for (int i=0; i< m.getParameterCount(); i++) { summary.put(new ObjectNode(i, ObjectType.parameter), new EscapeStatus(Escape.getInstance())); @@ -330,8 +368,12 @@ private void setParamsAsEscaping(SootMethod m, Map sum * changes on. */ - public void apply(SootMethod m, Unit u, PointsToGraph ptg, Map summary) { + public static void apply(SootMethod m, Unit u, PointsToGraph ptg, Map summary) { // System.err.println(u+" "+u.getClass().getName()); + + // System.out.println("PRIYAM soot unit " + u); + // System.out.println("PRIYAM soot ptg " + ptg); + if (u instanceof JAssignStmt) { JAssignStmtHandler.handle(m, u, ptg, summary); } else if (u instanceof JIdentityStmt) { diff --git a/src/config/StoreEscape.java b/src/config/StoreEscape.java index b1185bd80..8d595cbd2 100644 --- a/src/config/StoreEscape.java +++ b/src/config/StoreEscape.java @@ -1,7 +1,7 @@ package config; public class StoreEscape { - public static boolean MarkStoreEscaping = true; + public static boolean MarkStoreEscaping = false; public static boolean ReduceParamDependence = true; public static boolean MarkParamReturnEscaping = false; } diff --git a/src/handlers/JInvokeStmtHandler.java b/src/handlers/JInvokeStmtHandler.java index 0a5afce2b..a030cdd90 100644 --- a/src/handlers/JInvokeStmtHandler.java +++ b/src/handlers/JInvokeStmtHandler.java @@ -19,6 +19,9 @@ import java.util.Map; import java.util.ArrayList; import java.util.concurrent.ConcurrentHashMap; + +import analyser.StaticAnalyser; + import java.util.*; public class JInvokeStmtHandler { @@ -175,6 +178,14 @@ else if (expr instanceof JStaticInvokeExpr) { // Edge edge = edges.next(); SootMethod method = edge.tgt(); SootMethod srcMethod = edge.src(); + + // Recursion to first process the method + // if not already processed + if (!StaticAnalyser.methodsProcessed.contains(method)) { + // PRIYAM - Is correct? + StaticAnalyser.processMethod(method.getActiveBody()); + } + // System.out.println("Method: "+method + "isNative: "+method.isNative()); boolean isNative = method.isNative(); boolean iswhiteListed = !blacklistedNatives.contains(method.getBytecodeSignature()); @@ -183,14 +194,19 @@ else if (expr instanceof JStaticInvokeExpr) { } int paramCount = method.getParameterCount(); + Map> paramMapping = new HashMap>(); for (int i = 0; i < paramCount; i++) { ObjectNode obj = new ObjectNode(i, ObjectType.parameter); ConditionalValue cv = new ConditionalValue(method, obj, true); - if (edge.kind() == Kind.REFL_INVOKE) + if (edge.kind() == Kind.REFL_INVOKE) { ptg.cascadeCV((Local) args.get(1), cv, summary); - else if(edge.kind() == Kind.REFL_CONSTR_NEWINSTANCE) + paramMapping.put(obj, ptg.vars.get((Local) args.get(1))); + } + else if(edge.kind() == Kind.REFL_CONSTR_NEWINSTANCE) { ptg.cascadeCV((Local) args.get(0), cv, summary); + paramMapping.put(obj, ptg.vars.get((Local) args.get(0))); + } else { Value arg = args.get(i); if (arg.getType() instanceof RefType || arg.getType() instanceof ArrayType) @@ -203,9 +219,57 @@ else if(edge.kind() == Kind.REFL_CONSTR_NEWINSTANCE) } else ptg.cascadeCV((Local) args.get(i), cv, summary); + + paramMapping.put(obj, ptg.vars.get((Local) args.get(i))); } } } + + /* 2. + * Now, loop in the callie method's ptg to find if there + * exists any relationship/node between the params + * If exists, add the realtion for corresponding values in + * paramsMapping also + */ + PointsToGraph calliePTG = StaticAnalyser.ptgs.get(method); + System.out.println("PRIYAM METHOD: " + method); + System.out.println("PRIYAM PTGS: " + StaticAnalyser.ptgs); + System.out.println("PRIYAM calliePTG: " + calliePTG); + // If ptg gives error, ensure StaticAnalysis has been done + + for (int i = 0; i < paramCount; i++) { + ObjectNode obj = new ObjectNode(i, ObjectType.parameter); + Map> pointingTo = calliePTG.fields.get(obj); + + if (pointingTo == null) { + continue; + } + + for (Map.Entry> entry : pointingTo.entrySet()) { + for (ObjectNode fieldObj : entry.getValue()) { + System.out.println("There exists an edge from: " + obj + " to " + fieldObj + " by " + entry.getKey()); + if (fieldObj.type != ObjectType.parameter) { + continue; + } + + if (!paramMapping.containsKey(obj) || !paramMapping.containsKey(fieldObj)) { + // If paramsMapping does not have the object, it can happen if null is passed + continue; + } + + // Find paramsMapping for obj + // Find paramsMapping for fieldObj + // Add an edge from objs to fieldObjs + for (ObjectNode objInCaller : paramMapping.get(obj)) { + for (ObjectNode fieldObjInCaller : paramMapping.get(fieldObj)) { + System.out.println("There should exists an edge from: " + objInCaller + " to " + fieldObjInCaller + " by " + entry.getKey()); + ptg.WEAK_makeField(objInCaller, entry.getKey(), fieldObjInCaller); + } + } + } + } + } + } } } \ No newline at end of file diff --git a/src/main/GetSootArgs.java b/src/main/GetSootArgs.java index adb992a9b..a1e13877c 100644 --- a/src/main/GetSootArgs.java +++ b/src/main/GetSootArgs.java @@ -213,6 +213,7 @@ private String[] normal(String[] args){ "-p","cg.spark","on", "-p","cg","all-reachable", "-keep-offset", + "-f","J", // "-soot-classpath", cp, //"-prepend-classpath", "-keep-line-number", "-main-class", args[3], diff --git a/src/main/Main.java b/src/main/Main.java index c1f7c7328..1032a6e0a 100644 --- a/src/main/Main.java +++ b/src/main/Main.java @@ -1,5 +1,7 @@ package main; +import analyser.MethodsLinkingAnalyser; +import analyser.StackOrderAnalyser; import analyser.StaticAnalyser; import config.StoreEscape; import es.*; @@ -27,7 +29,6 @@ import java.util.Map; import java.util.*; import java.io.*; -import java.lang.*; import static utils.KillCallerOnly.kill; @@ -50,7 +51,7 @@ static void setStoreEscapeOptions(String[] args) { } } public static void main(String[] args) { - + // Generating soot args GetSootArgs g = new GetSootArgs(); String[] sootArgs = g.get(args); setStoreEscapeOptions(args); @@ -58,22 +59,17 @@ public static void main(String[] args) { System.out.println("Unable to generate args for soot!"); return; } + StaticAnalyser staticAnalyser = new StaticAnalyser(); CHATransform prepass = new CHATransform(); PackManager.v().getPack("wjap").add(new Transform("wjap.pre", prepass)); PackManager.v().getPack("jtp").add(new Transform("jtp.sample", staticAnalyser)); + long analysis_start = System.currentTimeMillis(); Options.v().parse(sootArgs); Scene.v().loadNecessaryClasses(); Scene.v().loadDynamicClasses(); List entryPoints = Scene.v().getEntryPoints(); - // SootClass sc = Scene.v().loadClassAndSupport("java.lang.CharacterData"); - // System.out.println(sc.getMethods()); - // Scene.v().forceResolve(sc.getName(), SootClass.BODIES); - // SootMethod tobeAdded = sc.getMethodByName("toUpperCaseEx"); - // System.out.println("Method: "+tobeAdded); - // // SootMethod tobeAdded = Scene.v().getMethod(""); - // entryPoints.add(tobeAdded); Chain appClasses = Scene.v().getClasses(); Iterator appClassItertator = appClasses.iterator(); @@ -92,56 +88,55 @@ public static void main(String[] args) { // System.out.println("SuperClass: "+aclass.getSuperclass()); } } - // aclass = Scene.v().loadClassAndSupport(aclass.getName()); - // aclass = Scene.v().forceResolve(aclass.getName(), SootClass.BODIES); - // // if (aclass.getName().contains("spec.validity.Digests")) { - // // System.out.println("Aclass spec: "+aclass.getName()+" : "+aclass.getMethodByName("crunch_jars")); - // // } - // System.out.println("Aclass: "+aclass.getName()+ " phantom: "+aclass.isPhantomClass()+" app: "+aclass.isApplicationClass()+" Concrete: "+ - // aclass.isConcrete()+" : " + aclass.getMethods()); - // // System.out.println(aclass.getMethods()); - // entryPoints.addAll(aclass.getMethods()); } - // System.out.println(entryPoints); - // if (true) - // return; - Scene.v().setEntryPoints(entryPoints); + Scene.v().setEntryPoints(entryPoints); PackManager.v().runPacks(); - // soot.Main.main(sootArgs); + long analysis_end = System.currentTimeMillis(); System.out.println("Static Analysis is done!"); System.out.println("Time Taken:"+(analysis_end-analysis_start)/1000F); - + System.out.println("BEFORE InterProcedural Linking"); + // printAllInfo(StaticAnalyser.ptgs, StaticAnalyser.summaries, StaticAnalyser.stackOrders, args[4]); + + // // Problem - not processing methods + + // // First, we add edges created due to callie function during method call + // analysis_start = System.currentTimeMillis(); + // // How to use spark here? + // // MethodsLinkingAnalyser methodsLinkingAnalyser = new MethodsLinkingAnalyser(); + // // PackManager.v().getPack("wjtp").add(new Transform("wjtp.ada", methodsLinkingAnalyser)); + // StackOrderAnalyser stackOrderAnalyser = new StackOrderAnalyser(); + // PackManager.v().getPack("jtp").add(new Transform("jtp.order", stackOrderAnalyser)); + // Scene.v().setEntryPoints(entryPoints); + // PackManager.v().runPacks(); + + + // Now we are going to find the stack ordering of the non escaping functions + CreateStackOrdering(); + analysis_end = System.currentTimeMillis(); + System.out.println("InterProcedural Linking is done!"); + System.out.println("Time Taken:"+(analysis_end-analysis_start)/1000F); + boolean useNewResolver = true; long res_start = System.currentTimeMillis(); - // printSummary(staticAnalyser.summaries); - // System.err.println(staticAnalyser.ptgs); - printAllInfo(StaticAnalyser.ptgs, staticAnalyser.summaries, args[4]); - // if (true) - // return; - // printCFG(); + System.out.println("BEFORE Resolver"); + printAllInfo(StaticAnalyser.ptgs, StaticAnalyser.summaries, StaticAnalyser.stackOrders, args[4]); if(useNewResolver) { - ReworkedResolver sr = new ReworkedResolver(staticAnalyser.summaries, - staticAnalyser.ptgs, - staticAnalyser.noBCIMethods); + ReworkedResolver sr = new ReworkedResolver( + StaticAnalyser.summaries, + StaticAnalyser.ptgs, + StaticAnalyser.noBCIMethods); long res_end = System.currentTimeMillis(); System.out.println("Resolution is done"); System.out.println("Time Taken in phase 1:"+(analysis_end-analysis_start)/1000F); System.out.println("Time Taken in phase 2:"+(res_end-res_start)/1000F); - - // System.out.println(staticAnalyser.summaries.size()+ " "+staticAnalyser.ptgs.size()); - - - HashMap> resolved = (HashMap) kill(sr.solvedSummaries); - printAllInfo(StaticAnalyser.ptgs, resolved, args[4]); - - saveStats(sr.existingSummaries, resolved, args[4], staticAnalyser.ptgs); - - printResForJVM(sr.solvedSummaries, args[2], args[4]); + System.out.println("AFTER Resolver"); + printAllInfo(StaticAnalyser.ptgs, StaticAnalyser.summaries, StaticAnalyser.stackOrders, args[4]); + printResForJVM(sr.solvedSummaries, StaticAnalyser.stackOrders, args[2], args[4]); } else { SummaryResolver sr = new SummaryResolver(); @@ -154,13 +149,72 @@ public static void main(String[] args) { HashMap> resolved = (HashMap) kill(sr.solvedSummaries); - printAllInfo(StaticAnalyser.ptgs, staticAnalyser.summaries, args[4]); + // printAllInfo(StaticAnalyser.ptgs, staticAnalyser.summaries, args[4]); - printAllInfo(StaticAnalyser.ptgs, resolved, args[4]); + // printAllInfo(StaticAnalyser.ptgs, resolved, args[4]); - saveStats(sr.existingSummaries, resolved, args[4], staticAnalyser.ptgs); + // saveStats(sr.existingSummaries, resolved, args[4], staticAnalyser.ptgs); - printResForJVM(sr.solvedSummaries, args[2], args[4]); + // printResForJVM(sr.solvedSummaries, args[2], args[4]); + } + } + + /** + * Performs dfs and finds the topological order + * @param node - Starting node of the dfs + * @param ptg - Points to graph + * @param visited - A visited array to have an idea of dfs + * @param topoOrder - The final result of the dfs - Topological Order + */ + static void topologicalSortDfs( + ObjectNode node, + PointsToGraph ptg, + HashSet visited, + ArrayList topoOrder) { + visited.add(node); + + Map> objectNodesMap = ptg.fields.get(node); + if (objectNodesMap != null) { + for (SootField sootField : objectNodesMap.keySet()) { + for (ObjectNode nextObject : objectNodesMap.get(sootField)) { + if (!visited.contains(nextObject)) { + topologicalSortDfs(nextObject, ptg, visited, topoOrder); + } + } + } + } + + topoOrder.add(node); + } + + /** + * Create Stack ordering for each ptg in the Static Analyser + */ + static void CreateStackOrdering() { + // We assumed that the PTGs exist in the StaticAnalyser + + System.out.println("PRIYAM - Starting topological sorting"); + for(SootMethod method : StaticAnalyser.ptgs.keySet()) { + PointsToGraph ptg = StaticAnalyser.ptgs.get(method); + + // TODO - First check if it is a DAG + // TO ASK - Peform a check before or combine with the + // topological dfs + // Perform topological sort for the ptg + + HashSet visited = new HashSet(); + ArrayList topoOrder = new ArrayList(); + + for(Set objectNodeSet : ptg.vars.values()) { + for (ObjectNode object : objectNodeSet) { + if (!visited.contains(object)) { + // System.out.println("PRIYAM object" + object); + topologicalSortDfs(object, ptg, visited, topoOrder); + } + } + } + + StaticAnalyser.stackOrders.put(method, topoOrder); } } @@ -215,8 +269,11 @@ public int compare(EscapeState a, EscapeState b) } } - private static void printAllInfo(Map ptgs, - Map> summaries, String opDir) { + private static void printAllInfo( + Map ptgs, + Map> summaries, + Map> stackOrders, + String opDir) { Path p_opDir = Paths.get(opDir); for (Map.Entry entry : ptgs.entrySet()) { @@ -229,7 +286,15 @@ private static void printAllInfo(Map ptgs, output.append("PTG:\n"); output.append(ptg.toString()); output.append("\nSummary\n"); - output.append(summaries.get(method).toString() + "\n"); + output.append(summaries.get(method).toString()); + + if (stackOrders.containsKey(method)) { + output.append("\nStackOrder\n"); + output.append(stackOrders.get(method).toString() + "\n\n"); + } else { + output.append("\nNo stack Ordering exists for : " + method + "\n\n"); + } + try { Files.write(p_opFile, output.toString().getBytes(StandardCharsets.UTF_8), Files.exists(p_opFile) ? StandardOpenOption.APPEND : StandardOpenOption.CREATE); @@ -240,6 +305,7 @@ private static void printAllInfo(Map ptgs, } } } + static String transformFuncSignature(String inputString) { StringBuilder finalString = new StringBuilder(); for(int i=1;i> summaries, String ipDir, String opDir) { + + static void printResForJVM( + Map> summaries, + Map> stackOrders, + String ipDir, + String opDir) { // Open File Path p_ipDir = Paths.get(ipDir); Path p_opDir = Paths.get(opDir); @@ -266,9 +337,10 @@ static void printResForJVM(Map> su HashMap summary = entry.getValue(); sb.append(transformFuncSignature(method.getBytecodeSignature())); sb.append(" "); - sb.append(GetListOfNoEscapeObjects.get(summary)); + sb.append(GetListOfNoEscapeObjects.get(summary, stackOrders.get(method))); sb.append("\n"); } + try { System.out.println("Trying to write to:" + p_opFile); Files.write(p_opFile, sb.toString().getBytes(StandardCharsets.UTF_8), diff --git a/src/stackOrdering/StackOrderer.java b/src/stackOrdering/StackOrderer.java new file mode 100644 index 000000000..15e40829a --- /dev/null +++ b/src/stackOrdering/StackOrderer.java @@ -0,0 +1,5 @@ +package stackOrdering; + +public class StackOrderer { + +} diff --git a/src/utils/GetListOfNoEscapeObjects.java b/src/utils/GetListOfNoEscapeObjects.java index 021f268d0..46ce44a13 100644 --- a/src/utils/GetListOfNoEscapeObjects.java +++ b/src/utils/GetListOfNoEscapeObjects.java @@ -10,16 +10,18 @@ import java.util.Map; public class GetListOfNoEscapeObjects { - public static String get(HashMap summary) { + public static String get( + HashMap summary, + ArrayList stackOrder) { ArrayList arr = new ArrayList<>(); - for (Map.Entry entry : summary.entrySet()) { - ObjectNode obj = entry.getKey(); - if(obj.type != ObjectType.internal) + for (ObjectNode obj : stackOrder) { + if (obj.type != ObjectType.internal) continue; - EscapeStatus es = entry.getValue(); - if (es.containsNoEscape()) arr.add(obj.ref); + EscapeStatus es = summary.get(obj); + if (es.containsNoEscape()) + arr.add(obj.ref); } - Collections.sort(arr); + String _ret = arr.toString(); return _ret; } diff --git a/tests/test1/Main.java b/tests/test1/Main.java index 64b3938fa..6ca52a26a 100644 --- a/tests/test1/Main.java +++ b/tests/test1/Main.java @@ -5,8 +5,7 @@ public static void main(String[] args) { Node C = new Node(); Node D = new Node(); A.n = B; - B.n = C; - C.n = D; - D.n = B; + B.n = D; + D.n = C; } } diff --git a/tests/test23/Main.java b/tests/test23/Main.java new file mode 100644 index 000000000..9cf2b64ff --- /dev/null +++ b/tests/test23/Main.java @@ -0,0 +1,13 @@ +public class Main { + public static void main(String[] args) { + Node A = new Node(); + Node B = new Node(); + Node C = new Node(); + Node D = new Node(); + Node E = new Node(); + A.n = B; + B.n = D; + B.m = E; + D.n = C; + } +} diff --git a/tests/test23/Node.java b/tests/test23/Node.java new file mode 100644 index 000000000..391eba7af --- /dev/null +++ b/tests/test23/Node.java @@ -0,0 +1,4 @@ +public class Node { + public Node n; + public Node m; +} diff --git a/tests/test24/Main.java b/tests/test24/Main.java new file mode 100644 index 000000000..bd8185af7 --- /dev/null +++ b/tests/test24/Main.java @@ -0,0 +1,33 @@ +public class Main { + public static void main(String[] args) { + } + + static void foo(Node node1, Node node2) { + Node A = new Node(); + Node B = new Node(); + Node C = new Node(); + Node D = new Node(); + Node E = new Node(); + // bar(A, B); + A.n = B; + + // if I make channges in staticAnalyser? + + Node x = A.n; + + // r10=[, ] + // Assumption 1 + // we do replacement of assignment + // statements after the whole pass + // How to consider for if else branch? + // For different branches? + + bar(x, C); + bar(D, E); + bar(node1, node2); + } + + static void bar(Node n1, Node n2) { + n1.n = n2; + } +} diff --git a/tests/test24/Node.java b/tests/test24/Node.java new file mode 100644 index 000000000..391eba7af --- /dev/null +++ b/tests/test24/Node.java @@ -0,0 +1,4 @@ +public class Node { + public Node n; + public Node m; +} diff --git a/tests/test25/Main.java b/tests/test25/Main.java new file mode 100644 index 000000000..e9b503f51 --- /dev/null +++ b/tests/test25/Main.java @@ -0,0 +1,26 @@ +public class Main { + public static void main(String[] args) { + } + + static void foo(Node node1, Node node2) { + Node A = new Node(); + Node B = new Node(); + Node C = new Node(); + Node D = new Node(); + Node E = new Node(); + bar(A, B); + bar(A, C); + bar(D, E); + bar(node1, node2); + } + + static void bar(Node n1, Node n2) { + Node F = new Node(); + n1.n = F; // we need to heapify F (address check) + F.n = n2; // no heapfication + + // Assumption 2 + // Theory -- If two objects are directly connected + // Then only we need stack order, else, we will not be needing any stack order + } +} diff --git a/tests/test25/Node.java b/tests/test25/Node.java new file mode 100644 index 000000000..391eba7af --- /dev/null +++ b/tests/test25/Node.java @@ -0,0 +1,4 @@ +public class Node { + public Node n; + public Node m; +} diff --git a/tests/test26/Main.java b/tests/test26/Main.java new file mode 100644 index 000000000..39b7ecb7d --- /dev/null +++ b/tests/test26/Main.java @@ -0,0 +1,19 @@ +public class Main { + public static void main(String[] args) { + Node x = new Node(); + Node y = new Node(); + foo(x, y); // There should come a linking for x and y from baz + } + + static void foo(Node node1, Node node2) { + bar(node1, node2); + } + + static void bar(Node n1, Node n2) { + baz(n1, n2); + } + + static void baz(Node p, Node q) { + p.n = q; // Linking the objects here + } +} diff --git a/tests/test26/Node.java b/tests/test26/Node.java new file mode 100644 index 000000000..391eba7af --- /dev/null +++ b/tests/test26/Node.java @@ -0,0 +1,4 @@ +public class Node { + public Node n; + public Node m; +} diff --git a/tests/test27/Main.java b/tests/test27/Main.java new file mode 100644 index 000000000..60829bb79 --- /dev/null +++ b/tests/test27/Main.java @@ -0,0 +1,32 @@ +public class Main { + public static void main(String[] args) { + // A recursive and multiple params test + } + + static void foo(Node node1, Node node2) { + Node A = new Node(); + Node B = new Node(); + Node C = new Node(); + Node D = new Node(); + Node E = new Node(); + Node F = new Node(); + Node G = new Node(); + + Main obj = new Main(); + obj.bar(A, B, C, D, E, F, G); + } + + void bar(Node n1, Node n2, Node n3, Node n4, Node n5, Node n6, Node n7) { + if (n7 == null) { + return; + } + + n1.n = n3; + n4.n = n5; + n5.n = n6; + n6.n = n2; + n2.n = n3; + + bar(n2, n3, n4, n5, n6, n7, null); + } +} diff --git a/tests/test27/Node.java b/tests/test27/Node.java new file mode 100644 index 000000000..391eba7af --- /dev/null +++ b/tests/test27/Node.java @@ -0,0 +1,4 @@ +public class Node { + public Node n; + public Node m; +}