diff --git a/README.md b/README.md index 1b6340b..6fc3f90 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ [![Tests](https://github.com/resess/Slicer4J/actions/workflows/maven_test.yml/badge.svg)](https://github.com/resess/Slicer4J/actions/workflows/maven_test.yml) drawing -This repository hosts Slicer4J, an accurate, low-overhead dynamic slicer for Java programs. -Slicer4J automatically generates a backward dynamic slice from a user selected executed statement and variables used in the statement (slicing criterion). -Slicer4J relies on soot which currently supports instrumenting programs compiled with up to Java 9. +This repository hosts Slicer4J, an accurate, low-overhead dynamic slicer for Java programs. +Slicer4J automatically generates a backward dynamic slice from a user selected executed statement and variables used in the statement (slicing criterion). +Slicer4J relies on soot which currently supports instrumenting programs compiled with up to Java 9. Contributions to this repo are most welcome! @@ -41,7 +41,7 @@ Khaled Ahmed, Mieszko Lis, and Julia Rubin. [Slicer4J: A Dynamic Slicer for Java * Clone the dynamic slicing core: https://github.com/resess/DynamicSlicingCore -* Requires Java Runtime Environment version 8. +* Requires Java Runtime Environment version 8. --- --- @@ -84,7 +84,7 @@ In that case, you can [change maximum heap size](https://docs.oracle.com/cd/E217 --- -### Slicer4J Mandatory Command Line Parameters: +### Slicer4J Mandatory Command Line Parameters: @@ -118,7 +118,7 @@ In that case, you can [change maximum heap size](https://docs.oracle.com/cd/E217 --- -### Slicer4J Optional Command Line Parameters: +### Slicer4J Optional Command Line Parameters:
@@ -168,9 +168,9 @@ In that case, you can [change maximum heap size](https://docs.oracle.com/cd/E217 --- -### User-defined method models: +### User-defined method models: -The following is an example for defining your own method models. +The following is an example for defining your own method models. For the methods in this class: ```Java @@ -233,7 +233,7 @@ For fields, we specify the signature of the field in `AccessPath` and its type i You can view the output of Slicer4J in 3 different formats: [Source Map](#Source-Map), [Raw Slice](#Raw-Slice), and [#Graph](Graph). -Let's see the output of slicing the `SliceMe` program (found under `benchmarks/SliceMe`): +Let's see the output of slicing the `SliceMe` program (found under `benchmarks/SliceMe`): ```Java 1. public class SliceMe { @@ -278,16 +278,18 @@ In this example, we slice from line 9 in the `SliceMe.java` file: `System.out.pr ### Source Map: This output is only generated if the JAR is compiled with debug information. -Slicer4J outputs a list of `files-name: source-code-line-number` for each statement that compose the slice. +Slicer4J outputs a list of `files-name: source-code-line-number` for each statement that compose the slice. This output is stored in the output folder in a file called `slice.log` +> **Note:** For programs using **lambdas** or containing **synthetic classes** (e.g., Compiler-generated inner classes), the line number will appear as `-1`. This indicates that the entry corresponds to a synthetic instruction with no direct source code origin, though the underlying data dependency is correctly tracked. + For the example, `slice.log` contains: ``` SliceMe:4 SliceMe:7 SliceMe:9 ``` -Which indicates that the slice is: +Which indicates that the slice is: ```Java 4. if (args.length > 0){ 7. parsed = null; @@ -318,7 +320,7 @@ Here we see that all statements are within the same thread (thread #1), and we s --- ### Graph: -Slicer4J outputs a [dot graph](https://graphviz.org/doc/info/lang.html) whose nodes are statements in the slice and edges are data and control dependencies between the statements. +Slicer4J outputs a [dot graph](https://graphviz.org/doc/info/lang.html) whose nodes are statements in the slice and edges are data and control dependencies between the statements. This output is stored in the output folder in a file called `slice-graph.pdf` @@ -329,7 +331,7 @@ For the example, `slice-graph.pdf` contents is shown here: Here we see the control dependencies (dashed edges) and data flow-dependencies (solid edges) between the Jimple statements from the raw slice. -For example, `$stack3 = lengthof parsed` is data-flow dependent on `parsed = null` through the variable `parsed`, which is written on the edge. +For example, `$stack3 = lengthof parsed` is data-flow dependent on `parsed = null` through the variable `parsed`, which is written on the edge. Also, `parsed = null` is control dependent on `if $stack2 <= 0 goto parsed = null`. --- diff --git a/Slicer4J/src/main/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/CommandParser.java b/Slicer4J/src/main/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/CommandParser.java index dec5c5e..5465e6d 100644 --- a/Slicer4J/src/main/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/CommandParser.java +++ b/Slicer4J/src/main/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/CommandParser.java @@ -35,6 +35,16 @@ public class CommandParser { options.addOption("d", "debug", false, "Enable debug"); // data options.addOption("once", "once", false, "Slice one step only"); // data options.addOption("noprint", "noprint", false, "Dont print slices"); // data + + /** + * Function-level slicing support. + * + *

Adds {@code --function-slice} option that changes slicing granularity + * from line-level to method-level. When enabled, the slicing criterion + * is expanded from a single source line to all trace statements within + * the containing method, producing a method-grained backward slice. + */ + options.addOption("fs", "function-slice", false, "Perform function-level slicing instead of line-level"); } @@ -73,6 +83,9 @@ public static Map parse(String[] args){ if (cmd.hasOption("noprint")) { parsed.put("noprint", "True"); } + if (cmd.hasOption("fs")) { + parsed.put("fs", "True"); + } } catch (ParseException e) { HelpFormatter formatter = new HelpFormatter(); formatter.printHelp(CMD_LINE_SYNTAX, options); diff --git a/Slicer4J/src/main/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/SlicePrettyPrinter.java b/Slicer4J/src/main/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/SlicePrettyPrinter.java new file mode 100644 index 0000000..f3aac6a --- /dev/null +++ b/Slicer4J/src/main/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/SlicePrettyPrinter.java @@ -0,0 +1,358 @@ +package ca.ubc.ece.resess.slicer.dynamic.slicer4j; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.io.FileUtils; + +import ca.ubc.ece.resess.slicer.dynamic.core.accesspath.AccessPath; +import ca.ubc.ece.resess.slicer.dynamic.core.slicer.DynamicSlice; +import ca.ubc.ece.resess.slicer.dynamic.core.statements.StatementInstance; +import guru.nidi.graphviz.attribute.Label; +import guru.nidi.graphviz.attribute.Style; +import guru.nidi.graphviz.attribute.ForNodeLink; +import guru.nidi.graphviz.engine.Format; +import guru.nidi.graphviz.engine.Graphviz; +import guru.nidi.graphviz.engine.GraphvizException; +import guru.nidi.graphviz.engine.Rasterizer; +import guru.nidi.graphviz.model.MutableGraph; +import static guru.nidi.graphviz.model.Factory.*; +import soot.toolkits.scalar.Pair; + +/** + * Function-level slicing output support. + * + *

Adds structured, human-readable slice reports that group results + * by method rather than individual source lines. Used in conjunction + * with the {@code --function-slice} CLI option. + */ +public class SlicePrettyPrinter { + + private SlicePrettyPrinter() { + throw new IllegalStateException("Utility class"); + } + + /** + * Prints the slice results grouped by method signature. + * + *

Function-level slicing contribution: produces a method-grained view + * of the backward slice, where each method lists the source lines that + * belong to it. Output is written to {@code slice-function.log}. + * + * @param outDir output directory for the report file + * @param slice the completed dynamic slice + */ + public static void printFunctionSlice(String outDir, DynamicSlice slice) { + Map> methodToLines = new LinkedHashMap<>(); + Map methodToFile = new LinkedHashMap<>(); + + for (Pair, Pair> entry : slice) { + StatementInstance si = entry.getO1().getO1(); + if (si == null) { + continue; + } + String sig = si.getMethod().getSignature(); + methodToLines.computeIfAbsent(sig, k -> new LinkedHashSet<>()) + .add(si.getJavaSourceFile() + ":" + si.getJavaSourceLineNo()); + methodToFile.putIfAbsent(sig, si.getJavaSourceFile()); + } + + List output = new ArrayList<>(); + output.add("Function-level slice (" + methodToLines.size() + " methods)"); + output.add(repeat("=", 72)); + + int idx = 1; + for (Map.Entry> e : methodToLines.entrySet()) { + output.add(String.format("[%d] %s", idx++, e.getKey())); + output.add(" Source: " + methodToFile.getOrDefault(e.getKey(), "UNKNOWN")); + output.add(" Lines: " + e.getValue().size()); + e.getValue().stream() + .sorted() + .forEach(l -> output.add(" " + l)); + output.add(""); + } + + String fileName = outDir + File.separator + "slice-function.log"; + try { + FileUtils.writeLines(new File(fileName), output); + } catch (IOException ex) { + System.err.println("Error writing function slice: " + ex.getMessage()); + } + } + + /** + * Generates a function-level DOT graph of the slice as a PDF. + * + *

Function-level slicing contribution: groups slice nodes by their + * containing method, producing a method-grained dependency graph where + * each node is a method and edges represent cross-method data or control + * dependencies. Output is written to {@code slice-graph-function.pdf}. + * + * @param outDir output directory for the graph file + * @param slice the completed dynamic slice + */ + public static void printFunctionDotGraph(String outDir, DynamicSlice slice) { + MutableGraph g = mutGraph("Function-Level Slice").setDirected(true); + + // Collect unique method signatures and their display names + Map methodLabels = new LinkedHashMap<>(); + for (Pair, Pair> entry : slice) { + StatementInstance dest = entry.getO1().getO1(); + StatementInstance src = entry.getO2().getO1(); + if (dest != null) { + methodLabels.putIfAbsent(dest.getMethod().getSignature(), + shortenSignature(dest.getMethod().getSignature())); + } + if (src != null) { + methodLabels.putIfAbsent(src.getMethod().getSignature(), + shortenSignature(src.getMethod().getSignature())); + } + } + + // Build method-level edges, deduplicating (data overrides control) + Map methodEdges = new LinkedHashMap<>(); + for (Pair, Pair> entry : slice) { + StatementInstance dest = entry.getO1().getO1(); + StatementInstance src = entry.getO2().getO1(); + if (dest == null || src == null) { + continue; + } + String dm = dest.getMethod().getSignature(); + String sm = src.getMethod().getSignature(); + if (dm.equals(sm)) { + continue; // skip intra-method edges + } + String edgeType = slice.getEdges(dest.getLineNo(), src.getLineNo()); + String key = sm + "->" + dm; + // Data edges take priority over control edges + if (!methodEdges.containsKey(key) || "data".equals(edgeType)) { + methodEdges.put(key, edgeType); + } + } + + // Create nodes + Map nodes = new LinkedHashMap<>(); + for (Map.Entry e : methodLabels.entrySet()) { + guru.nidi.graphviz.model.Node n = node(e.getValue()); + nodes.put(e.getKey(), n); + g.add(n); + } + + // Create edges + for (Map.Entry e : methodEdges.entrySet()) { + String[] parts = e.getKey().split("->"); + String srcSig = parts[0]; + String destSig = parts[1]; + String edgeType = e.getValue(); + guru.nidi.graphviz.model.Node srcNode = nodes.get(srcSig); + guru.nidi.graphviz.model.Node destNode = nodes.get(destSig); + if (srcNode != null && destNode != null) { + Style edgeStyle = "control".equals(edgeType) ? Style.DASHED : Style.SOLID; + g.add(srcNode.link(to(destNode).with(edgeStyle, Label.of(edgeType)))); + } + } + + try { + Graphviz.fromGraph(g).rasterize(Rasterizer.builtIn("pdf")) + .toFile(new File(outDir + File.separator + "slice-graph-function.pdf")); + } catch (IOException | GraphvizException ex) { + System.err.println("Error writing function dot graph: " + ex.getMessage()); + } + } + + /** + * Pretty-prints a human-readable slice report with method grouping, + * source line listing, and inter-method dependency edges. + * + *

Function-level slicing contribution: produces a structured report + * ({@code slice-pretty.log}) that helps developers understand which + * methods participate in the slice and how they depend on each other. + * + * @param outDir output directory for the report file + * @param slice the completed dynamic slice + * @param slicePositions the trace positions used as slicing criterion + * @param criterionStmts the StatementInstances used as slicing criterion + */ + public static void printPrettySlice(String outDir, DynamicSlice slice, + List slicePositions, List criterionStmts) { + + // Group slice entries by destination method + Map> methodGroups = new LinkedHashMap<>(); + Map> methodDeps = new LinkedHashMap<>(); + Map methodToFile = new LinkedHashMap<>(); + Set seenLines = new LinkedHashSet<>(); + + for (Pair, Pair> entry : slice) { + StatementInstance dest = entry.getO1().getO1(); + StatementInstance src = entry.getO2().getO1(); + if (dest == null || src == null) { + continue; + } + + String edgeType = slice.getEdges(dest.getLineNo(), src.getLineNo()); + String destMethod = dest.getMethod().getSignature(); + String srcMethod = src.getMethod().getSignature(); + + methodGroups.computeIfAbsent(destMethod, k -> new ArrayList<>()).add(dest); + methodToFile.putIfAbsent(destMethod, dest.getJavaSourceFile()); + + if (!destMethod.equals(srcMethod)) { + String depDesc = String.format("%s <-- %s (%s:%d)", + edgeType, + shortenSignature(srcMethod), + src.getJavaSourceFile(), src.getJavaSourceLineNo()); + methodDeps.computeIfAbsent(destMethod, k -> new LinkedHashSet<>()).add(depDesc); + } + } + + // Determine target method from criterion + String targetMethod = ""; + if (criterionStmts != null && !criterionStmts.isEmpty() && criterionStmts.get(0) != null) { + targetMethod = criterionStmts.get(0).getMethod().getSignature(); + } + + // Count unique source lines in the slice + int totalLines = 0; + for (List stmts : methodGroups.values()) { + Set unique = new LinkedHashSet<>(); + for (StatementInstance si : stmts) { + unique.add(si.getJavaSourceFile() + ":" + si.getJavaSourceLineNo()); + } + totalLines += unique.size(); + } + + // Build the report + List output = new ArrayList<>(); + output.add(repeat("=", 80)); + output.add(" SLICE REPORT"); + output.add(" Mode: FUNCTION-LEVEL"); + output.add(" Target method: " + targetMethod); + output.add(" Criterion size: " + (criterionStmts != null ? criterionStmts.size() : 0) + " statements"); + output.add(" Slice size: " + totalLines + " source lines across " + methodGroups.size() + " methods"); + output.add(repeat("=", 80)); + output.add(""); + + // Per-method detail + int idx = 1; + for (Map.Entry> e : methodGroups.entrySet()) { + String methodSig = e.getKey(); + output.add(repeat("-", 80)); + output.add(String.format("[%d] %s", idx++, methodSig)); + output.add(" Source: " + methodToFile.getOrDefault(methodSig, "UNKNOWN")); + + // Deduplicate and sort source lines + Set uniqueLines = new LinkedHashSet<>(); + for (StatementInstance si : e.getValue()) { + uniqueLines.add(si.getJavaSourceFile() + ":" + si.getJavaSourceLineNo()); + } + output.add(" Lines in slice (" + uniqueLines.size() + "):"); + uniqueLines.stream() + .sorted() + .forEach(l -> output.add(" " + l)); + + // Dependencies on other methods + Set deps = methodDeps.get(methodSig); + if (deps != null && !deps.isEmpty()) { + output.add(" Inter-method dependencies:"); + deps.stream().sorted().forEach(d -> output.add(" " + d)); + } + output.add(""); + } + + // Method-level dependency summary + Map> methodGraph = new LinkedHashMap<>(); + for (Pair, Pair> entry : slice) { + StatementInstance dest = entry.getO1().getO1(); + StatementInstance src = entry.getO2().getO1(); + if (dest == null || src == null) { + continue; + } + String dm = dest.getMethod().getSignature(); + String sm = src.getMethod().getSignature(); + if (!dm.equals(sm)) { + String edgeType = slice.getEdges(dest.getLineNo(), src.getLineNo()); + methodGraph.computeIfAbsent(dm, k -> new LinkedHashSet<>()) + .add(shortenSignature(sm) + " (" + edgeType + ")"); + } + } + + if (!methodGraph.isEmpty()) { + output.add(repeat("=", 80)); + output.add(" METHOD-LEVEL DEPENDENCY GRAPH"); + output.add(repeat("=", 80)); + for (Map.Entry> e : methodGraph.entrySet()) { + String caller = shortenSignature(e.getKey()); + for (String callee : e.getValue()) { + output.add(" " + caller + " --> " + callee); + } + } + output.add(""); + } + + output.add(repeat("=", 80)); + output.add(" End of report"); + output.add(repeat("=", 80)); + + String fileName = outDir + File.separator + "slice-pretty.log"; + try { + FileUtils.writeLines(new File(fileName), output); + } catch (IOException ex) { + System.err.println("Error writing pretty slice: " + ex.getMessage()); + } + } + + /** + * Shortens a Soot method signature for display. + * Converts {@code } to {@code Foo.bar()}. + */ + private static String shortenSignature(String sig) { + if (sig == null || sig.isEmpty()) { + return sig; + } + String inner = sig.startsWith("<") && sig.endsWith(">") ? sig.substring(1, sig.length() - 1) : sig; + int colon = inner.lastIndexOf(':'); + if (colon < 0) { + return inner; + } + String className = inner.substring(0, colon); + String methodPart = inner.substring(colon + 1).trim(); + + // Extract short class name + String shortClass = className; + int lastDot = className.lastIndexOf('.'); + if (lastDot >= 0) { + shortClass = className.substring(lastDot + 1); + } + + // Extract method name (before the first space, which separates return type) + String methodName = methodPart; + int firstSpace = methodPart.indexOf(' '); + if (firstSpace >= 0) { + methodName = methodPart.substring(firstSpace + 1); + } + + // Remove parameter types for brevity + int parenOpen = methodName.indexOf('('); + if (parenOpen >= 0) { + methodName = methodName.substring(0, parenOpen) + "()"; + } + + return shortClass + "." + methodName; + } + + private static String repeat(String s, int count) { + StringBuilder sb = new StringBuilder(s.length() * count); + for (int i = 0; i < count; i++) { + sb.append(s); + } + return sb.toString(); + } +} diff --git a/Slicer4J/src/main/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/Slicer.java b/Slicer4J/src/main/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/Slicer.java index 06a7654..e772cf7 100644 --- a/Slicer4J/src/main/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/Slicer.java +++ b/Slicer4J/src/main/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/Slicer.java @@ -12,6 +12,7 @@ import java.time.format.DateTimeFormatter; import java.util.*; import java.util.Map.Entry; +import java.util.stream.Collectors; import com.google.common.base.Optional; @@ -200,16 +201,15 @@ public DynamicSlice directStatementDependency(StatementInstance start, boolean d public void runInstrumentedJarFromMain(String pathToJar, String mainClass, String mainArguments) throws IOException, InterruptedException { ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "java -Xmx8g -cp " + pathToJar + " " + mainClass + " " + mainArguments+ " | grep \"SLICING\""); Process p = pb.start(); - p.waitFor(); - BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); - BufferedWriter writer = Files.newBufferedWriter(Paths.get(outDir + File.separator + "trace.log")); - String readline; - while ((readline = reader.readLine()) != null) { - writer.write(readline); - writer.write("\n"); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + BufferedWriter writer = Files.newBufferedWriter(Paths.get(outDir + File.separator + "trace.log"))) { + String readline; + while ((readline = reader.readLine()) != null) { + writer.write(readline); + writer.write("\n"); + } } - writer.close(); - reader.close(); + p.waitFor(); } public static void main(String [] args) { @@ -332,7 +332,35 @@ public static void main(String [] args) { for (Integer backSlicePos: slicer.backwardSlicePositions) { stmts.add(icdg.mapNoUnits(backSlicePos)); } - + + // Function-level slicing (--function-slice): expand the slicing criterion + // from a single source line to all trace statements within the containing + // method, producing a method-grained backward slice. + boolean functionSlice = commands.containsKey("fs"); + if (functionSlice) { + Set targetMethods = new HashSet<>(); + for (StatementInstance stmt : stmts) { + if (stmt != null) { + targetMethods.add(stmt.getMethod().getSignature()); + } + } + List expandedPositions = new ArrayList<>(); + for (StatementInstance si : icdg.getTraceList()) { + if (si != null && targetMethods.contains(si.getMethod().getSignature())) { + expandedPositions.add(si.getLineNo()); + } + } + AnalysisLogger.log(true, "Function-level slice: expanded from {} to {} trace positions across method(s) {}", + slicer.backwardSlicePositions.size(), expandedPositions.size(), targetMethods); + slicer.setBackwardSlicePositions( + expandedPositions.stream().map(String::valueOf).collect(Collectors.joining("-"))); + slicer.setVariableString("*"); + stmts.clear(); + for (Integer backSlicePos : slicer.backwardSlicePositions) { + stmts.add(icdg.mapNoUnits(backSlicePos)); + } + } + List variables = new ArrayList<>(); if (!slicer.variableString.equals("*")) { String[] split = slicer.variableString.split("-"); @@ -375,6 +403,13 @@ public String toString() { String resultFileName = slicer.outDir + File.separator + "result_" +mode+"_"+ dtf.format(now) + ".csv"; SlicePrinter.printToCSV(resultFileName, dynamicSlice); + // Function-level slicing output: method-grouped slice and human-readable report + if (functionSlice) { + SlicePrettyPrinter.printFunctionSlice(slicer.outDir, dynamicSlice); + SlicePrettyPrinter.printPrettySlice(slicer.outDir, dynamicSlice, slicer.backwardSlicePositions, stmts); + SlicePrettyPrinter.printFunctionDotGraph(slicer.outDir, dynamicSlice); + } + AnalysisLogger.log(true, "Slice size: {}", dynamicSlice.size()); terminate(slicer.outDir, mode, startTime); } diff --git a/Slicer4J/src/main/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/instrumenter/JavaInstrumenter.java b/Slicer4J/src/main/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/instrumenter/JavaInstrumenter.java index d29ad7d..e30771b 100644 --- a/Slicer4J/src/main/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/instrumenter/JavaInstrumenter.java +++ b/Slicer4J/src/main/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/instrumenter/JavaInstrumenter.java @@ -1,10 +1,12 @@ package ca.ubc.ece.resess.slicer.dynamic.slicer4j.instrumenter; +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -253,7 +255,10 @@ public void start (String options, String staticLogFile, String jarPath, String try { classesFile.delete(); StringBuilder instrClasses = new StringBuilder(); - List orderedClasses = new ArrayList<>(instrumentedClasses); + List orderedClasses = new ArrayList<>(); + for (String className : instrumentedClasses) { + orderedClasses.add(className); + } orderedClasses.sort((a, b) -> a.compareTo(b)); for (String className : orderedClasses) { instrClasses.append(className); @@ -322,7 +327,18 @@ public void start (String options, String staticLogFile, String jarPath, String jarOptions = "uf"; } - Process p = Runtime.getRuntime().exec("jar " + jarOptions + " " + jarName + " " + clazzFile, null, new File(Slicer.SOOT_OUTPUT_STRING)); + List cmd = new ArrayList<>(); + cmd.add("jar"); + cmd.add(jarOptions); + cmd.add(jarName); + cmd.addAll(instrumentedClasses.subList(i, minIndex)); + ProcessBuilder pb = new ProcessBuilder(cmd); + pb.directory(new File(Slicer.SOOT_OUTPUT_STRING)); + pb.redirectErrorStream(true); + Process p = pb.start(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()))) { + while (reader.readLine() != null) {} + } p.waitFor(); // String output = IOUtils.toString(p.getInputStream()); // String errorOutput = IOUtils.toString(p.getErrorStream()); diff --git a/Slicer4J/src/test/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/BenchTests.java b/Slicer4J/src/test/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/BenchTests.java index 0703b93..0d4394e 100644 --- a/Slicer4J/src/test/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/BenchTests.java +++ b/Slicer4J/src/test/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/BenchTests.java @@ -2,7 +2,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; - import java.io.File; import java.io.IOException; import java.nio.file.Path; @@ -19,214 +18,393 @@ import ca.ubc.ece.resess.slicer.dynamic.core.graph.DynamicControlFlowGraph; - public class BenchTests { - Path root = Paths.get(".").normalize().toAbsolutePath(); - Path slicerPath = Paths.get(root.getParent().toString(), "scripts"); - Path outDir = Paths.get(slicerPath.toString(), "testTempDir"); - Path sliceLogger = Paths.get(root.getParent().getParent().toString(), "DynamicSlicingCore" + File.separator + "DynamicSlicingLoggingClasses" + File.separator + "DynamicSlicingLogger.jar"); - - @BeforeAll - static void preCleanUp() throws IOException { - TestUtils.cleanWorkingDirectory(); - } - - @AfterEach - void postCleanUp() throws IOException { - TestUtils.cleanWorkingDirectory(); - } - - - @Test - void javaslicer_bench1() throws IOException, InterruptedException { - Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "javaslicer-bench1-intra-procedural"); - String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "javaslicer-bench1-intra-procedural-1.0.0.jar").toString(); - - TestUtils.buildJar(testPath); - - Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); - - String instrumentedJar = slicer.instrument(); - slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", "2"); - - DynamicControlFlowGraph dcfg = slicer.prepareGraph(); - slicer.printGraph(dcfg); - - Integer tracePositionToSliceFrom = 8; - Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); - - Set expected = new HashSet<>(Arrays.asList("Bench:5", "Bench:4", "Bench:7", "Bench:6", "Bench:8")); - - assertEquals(expected, sliceLines); - } - - @Test - void javaslicer_bench2() throws IOException, InterruptedException { - Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "javaslicer-bench2-inter-procedural"); - String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "javaslicer-bench2-inter-procedural-1.0.0.jar").toString(); - - TestUtils.buildJar(testPath); - - Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); - - String instrumentedJar = slicer.instrument(); - slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", "2"); - - DynamicControlFlowGraph dcfg = slicer.prepareGraph(); - slicer.printGraph(dcfg); - - Integer tracePositionToSliceFrom = 12; - Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); - - Set expected = new HashSet<>(Arrays.asList("Bench:12", "Bench:4", "Bench:7", "Bench:6", "Bench:8")); - - assertEquals(expected, sliceLines); - } - - @Test - void javaslicer_bench3() throws IOException, InterruptedException { - Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "javaslicer-bench3-exceptions"); - String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "javaslicer-bench3-exceptions-1.0.0.jar").toString(); - - TestUtils.buildJar(testPath); - - Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); - slicer.setDebug(true); - String instrumentedJar = slicer.instrument(); - slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", ""); - - DynamicControlFlowGraph dcfg = slicer.prepareGraph(); - slicer.printGraph(dcfg); - - Integer tracePositionToSliceFrom = 20; - Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); - - Set expected = new HashSet<>(Arrays.asList("Bench:33", "Bench:19", "Bench:29", "Bench:4", "Bench:17", "Bench:28")); - - assertEquals(expected, sliceLines); - } - - @Test - void slicer4j_bench1() throws IOException, InterruptedException { - Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "slicer4j-bench1-multiple-threads"); - String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "slicer4j-bench1-multiple-threads-1.0.0.jar").toString(); - - TestUtils.buildJar(testPath); - - Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); - slicer.setDebug(true); - String instrumentedJar = slicer.instrument(); - slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", ""); - - DynamicControlFlowGraph dcfg = slicer.prepareGraph(); - slicer.printGraph(dcfg); - - Integer tracePositionToSliceFrom = 38; - Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); - - Set expected = new HashSet<>(Arrays.asList("Bench:12", "Producer:28", "Bench:14", "Consumer:43", "Consumer:40")); - - assertEquals(expected, sliceLines); - } - - @Test - void slicer4j_bench2() throws IOException, InterruptedException { - Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "slicer4j-bench2-native-framework"); - String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "slicer4j-bench2-native-framework-1.0.0.jar").toString(); - - TestUtils.buildJar(testPath); - - Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); - slicer.setDebug(true); - String instrumentedJar = slicer.instrument(); - slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", "0 4"); - - DynamicControlFlowGraph dcfg = slicer.prepareGraph(); - slicer.printGraph(dcfg); - - Integer tracePositionToSliceFrom = 21; - Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); - - Set expected = new HashSet<>(Arrays.asList("Bench:5", "Bench:4", "Bench:7", "Bench:6", "Bench:9", "Bench:8")); - - assertEquals(expected, sliceLines); - } - - @Test - void slicer4j_bench3() throws IOException, InterruptedException { - Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "slicer4j-bench3-java-9-constructs"); - String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "slicer4j-bench3-java-9-constructs-1.0.0.jar").toString(); - - TestUtils.buildJar(testPath); - - Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); - slicer.setDebug(true); - String instrumentedJar = slicer.instrument(); - slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", "3 4"); - - DynamicControlFlowGraph dcfg = slicer.prepareGraph(); - slicer.printGraph(dcfg); - - Integer tracePositionToSliceFrom = 23; - List sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom).stream() - .sorted((a, b) -> a.compareTo(b)) - .collect(Collectors.toList()); - - List expected = Arrays.asList("Bench:13", "Bench:5", "Bench:7", "Bench:6", "Bench:9", "Bench:8").stream() - .sorted((a, b) -> a.compareTo(b)) - .collect(Collectors.toList()); - - assertEquals(expected, sliceLines); - } - - @Test - void slicer4j_bench4() throws IOException, InterruptedException { - Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "slicer4j-bench4-instrumentation-classes"); - String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "slicer4j-bench4-instrumentation-classes-1.0.0.jar").toString(); - - TestUtils.buildJar(testPath); - - Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); - slicer.setDebug(true); - String instrumentedJar = slicer.instrument(); - slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", "22"); - - DynamicControlFlowGraph dcfg = slicer.prepareGraph(); - slicer.printGraph(dcfg); - - Integer tracePositionToSliceFrom = 11; - Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); - - Set expected = new HashSet<>(Arrays.asList("Bench:10", "Bench:7", "Bench:6", "Bench:9", "Bench:8")); - - assertEquals(expected, sliceLines); - } - - @Test - void slicer4j_bench5() throws IOException, InterruptedException { - Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "slicer4j-bench5-static-constructor"); - String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "slicer4j-bench5-static-constructor-1.0.0.jar").toString(); - - TestUtils.buildJar(testPath); - - Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); - slicer.setDebug(true); - String instrumentedJar = slicer.instrument(); - slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", "22"); - - DynamicControlFlowGraph dcfg = slicer.prepareGraph(); - slicer.printGraph(dcfg); - - Integer tracePositionToSliceFrom = 14; - List sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom).stream() - .sorted((a, b) -> a.compareTo(b)) - .collect(Collectors.toList()); - - List expected = Arrays.asList("Bench:12", "Bench:2", "Bench:4", "Bench:7", "Bench:6", "Bench:8").stream() - .sorted((a, b) -> a.compareTo(b)) - .collect(Collectors.toList()); - - assertEquals(expected, sliceLines); - } + Path root = Paths.get(".").normalize().toAbsolutePath(); + Path slicerPath = Paths.get(root.getParent().toString(), "scripts"); + Path outDir = Paths.get(slicerPath.toString(), "testTempDir"); + Path sliceLogger = Paths.get(root.getParent().getParent().toString(), "DynamicSlicingCore" + File.separator + + "DynamicSlicingLoggingClasses" + File.separator + "DynamicSlicingLogger.jar"); + + @BeforeAll + static void preCleanUp() throws IOException { + TestUtils.cleanWorkingDirectory(); + } + + @AfterEach + void postCleanUp() throws IOException { + TestUtils.cleanWorkingDirectory(); + } + + @Test + void javaslicer_bench1() throws IOException, InterruptedException { + Path testPath = Paths.get(root.getParent().toString(), + "benchmarks" + File.separator + "javaslicer-bench1-intra-procedural"); + String jarPath = Paths + .get(testPath.toString(), + "target" + File.separator + + "javaslicer-bench1-intra-procedural-1.0.0.jar") + .toString(); + + TestUtils.buildJar(testPath); + + Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); + + String instrumentedJar = slicer.instrument(); + slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", "2"); + + DynamicControlFlowGraph dcfg = slicer.prepareGraph(); + slicer.printGraph(dcfg); + + Integer tracePositionToSliceFrom = 8; + Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); + + Set expected = new HashSet<>( + Arrays.asList("Bench:5", "Bench:4", "Bench:7", "Bench:6", "Bench:8")); + + assertEquals(expected, sliceLines); + } + + @Test + void javaslicer_bench2() throws IOException, InterruptedException { + Path testPath = Paths.get(root.getParent().toString(), + "benchmarks" + File.separator + "javaslicer-bench2-inter-procedural"); + String jarPath = Paths + .get(testPath.toString(), + "target" + File.separator + + "javaslicer-bench2-inter-procedural-1.0.0.jar") + .toString(); + + TestUtils.buildJar(testPath); + + Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); + + String instrumentedJar = slicer.instrument(); + slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", "2"); + + DynamicControlFlowGraph dcfg = slicer.prepareGraph(); + slicer.printGraph(dcfg); + + Integer tracePositionToSliceFrom = 12; + Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); + + Set expected = new HashSet<>( + Arrays.asList("Bench:12", "Bench:4", "Bench:7", "Bench:6", "Bench:8")); + + assertEquals(expected, sliceLines); + } + + @Test + void javaslicer_bench3() throws IOException, InterruptedException { + Path testPath = Paths.get(root.getParent().toString(), + "benchmarks" + File.separator + "javaslicer-bench3-exceptions"); + String jarPath = Paths + .get(testPath.toString(), + "target" + File.separator + "javaslicer-bench3-exceptions-1.0.0.jar") + .toString(); + + TestUtils.buildJar(testPath); + + Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); + slicer.setDebug(true); + String instrumentedJar = slicer.instrument(); + slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", ""); + + DynamicControlFlowGraph dcfg = slicer.prepareGraph(); + slicer.printGraph(dcfg); + + Integer tracePositionToSliceFrom = 20; + Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); + + Set expected = new HashSet<>( + Arrays.asList("Bench:33", "Bench:19", "Bench:29", "Bench:4", "Bench:17", "Bench:28")); + + assertEquals(expected, sliceLines); + } + + @Test + void slicer4j_bench1() throws IOException, InterruptedException { + Path testPath = Paths.get(root.getParent().toString(), + "benchmarks" + File.separator + "slicer4j-bench1-multiple-threads"); + String jarPath = Paths + .get(testPath.toString(), + "target" + File.separator + + "slicer4j-bench1-multiple-threads-1.0.0.jar") + .toString(); + + TestUtils.buildJar(testPath); + + Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); + slicer.setDebug(true); + String instrumentedJar = slicer.instrument(); + slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", ""); + + DynamicControlFlowGraph dcfg = slicer.prepareGraph(); + slicer.printGraph(dcfg); + + Integer tracePositionToSliceFrom = 38; + Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); + + Set expected = new HashSet<>( + Arrays.asList("Bench:12", "Producer:28", "Bench:14", "Consumer:43", "Consumer:40")); + + assertEquals(expected, sliceLines); + } + + @Test + void slicer4j_bench2() throws IOException, InterruptedException { + Path testPath = Paths.get(root.getParent().toString(), + "benchmarks" + File.separator + "slicer4j-bench2-native-framework"); + String jarPath = Paths + .get(testPath.toString(), + "target" + File.separator + + "slicer4j-bench2-native-framework-1.0.0.jar") + .toString(); + + TestUtils.buildJar(testPath); + + Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); + slicer.setDebug(true); + String instrumentedJar = slicer.instrument(); + slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", "0 4"); + + DynamicControlFlowGraph dcfg = slicer.prepareGraph(); + slicer.printGraph(dcfg); + + Integer tracePositionToSliceFrom = 21; + Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); + + Set expected = new HashSet<>( + Arrays.asList("Bench:5", "Bench:4", "Bench:7", "Bench:6", "Bench:9", "Bench:8")); + + assertEquals(expected, sliceLines); + } + + @Test + void slicer4j_bench3() throws IOException, InterruptedException { + Path testPath = Paths.get(root.getParent().toString(), + "benchmarks" + File.separator + "slicer4j-bench3-java-9-constructs"); + String jarPath = Paths + .get(testPath.toString(), + "target" + File.separator + + "slicer4j-bench3-java-9-constructs-1.0.0.jar") + .toString(); + + TestUtils.buildJar(testPath); + + Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); + slicer.setDebug(true); + String instrumentedJar = slicer.instrument(); + slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", "3 4"); + + DynamicControlFlowGraph dcfg = slicer.prepareGraph(); + slicer.printGraph(dcfg); + + Integer tracePositionToSliceFrom = 23; + List sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom) + .stream() + .sorted((a, b) -> a.compareTo(b)) + .collect(Collectors.toList()); + + List expected = Arrays.asList("Bench:13", "Bench:5", "Bench:7", "Bench:6", "Bench:9", "Bench:8") + .stream() + .sorted((a, b) -> a.compareTo(b)) + .collect(Collectors.toList()); + + assertEquals(expected, sliceLines); + } + + @Test + void slicer4j_bench4() throws IOException, InterruptedException { + Path testPath = Paths.get(root.getParent().toString(), + "benchmarks" + File.separator + "slicer4j-bench4-instrumentation-classes"); + String jarPath = Paths.get(testPath.toString(), + "target" + File.separator + "slicer4j-bench4-instrumentation-classes-1.0.0.jar") + .toString(); + + TestUtils.buildJar(testPath); + + Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); + slicer.setDebug(true); + String instrumentedJar = slicer.instrument(); + slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", "22"); + + DynamicControlFlowGraph dcfg = slicer.prepareGraph(); + slicer.printGraph(dcfg); + + Integer tracePositionToSliceFrom = 11; + Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); + + Set expected = new HashSet<>( + Arrays.asList("Bench:10", "Bench:7", "Bench:6", "Bench:9", "Bench:8")); + + assertEquals(expected, sliceLines); + } + + @Test + void slicer4j_bench5() throws IOException, InterruptedException { + Path testPath = Paths.get(root.getParent().toString(), + "benchmarks" + File.separator + "slicer4j-bench5-static-constructor"); + String jarPath = Paths + .get(testPath.toString(), + "target" + File.separator + + "slicer4j-bench5-static-constructor-1.0.0.jar") + .toString(); + + TestUtils.buildJar(testPath); + + Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); + slicer.setDebug(true); + String instrumentedJar = slicer.instrument(); + slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", "22"); + + DynamicControlFlowGraph dcfg = slicer.prepareGraph(); + slicer.printGraph(dcfg); + + Integer tracePositionToSliceFrom = 14; + List sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom) + .stream() + .sorted((a, b) -> a.compareTo(b)) + .collect(Collectors.toList()); + + List expected = Arrays.asList("Bench:12", "Bench:2", "Bench:4", "Bench:7", "Bench:6", "Bench:8") + .stream() + .sorted((a, b) -> a.compareTo(b)) + .collect(Collectors.toList()); + + assertEquals(expected, sliceLines); + } + + // This issue is not fixable. Please see #Issue 42 for an explanation of why + // this test is commented out + // @Test + // void issue_42_slicer4j_bench_const_prop_simple() throws IOException, + // InterruptedException { + // Path testPath = Paths.get(root.getParent().toString(), + // "benchmarks" + File.separator + "issue-42-slicer4j-bench-const-prop-simple"); + // String jarPath = Paths.get(testPath.toString(), + // "target" + File.separator + + // "issue-42-slicer4j-bench-const-prop-simple-1.0.0.jar") + // .toString(); + + // TestUtils.buildJar(testPath); + + // Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); + // slicer.setDebug(true); + // String instrumentedJar = slicer.instrument(); + // slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", ""); + + // DynamicControlFlowGraph dcfg = slicer.prepareGraph(); + // slicer.printGraph(dcfg); + + // // Slicing criterion: ConstPropSimple:7 (d) + // // From the user, lines 3, 4, 5, 6, 7 are the IDEAL expected slice + // // Trace position corresponds to line 7. We'll search for it dynamically + // later, + // // but for now we put a placeholder 7 or the first instance of line 7. + // List tracePositions = TestUtils.getTracePositionFromSourceLine(7, + // "Bench", dcfg); + // Integer tracePositionToSliceFrom = tracePositions.isEmpty() ? 7 : + // tracePositions.get(0); + + // Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, + // tracePositionToSliceFrom); + + // Set expected = new HashSet<>( + // Arrays.asList("Bench:3", "Bench:4", "Bench:5", "Bench:6", "Bench:7")); + + // System.out.println("=== issue_42_slicer4j_bench_const_prop_simple ==="); + // System.out.println("Expected slice: " + expected); + // System.out.println("Actual slice: " + sliceLines); + // System.out.println("==================================================="); + + // assertEquals(expected, sliceLines); + // } + + // @Test + // void issue_42_slicer4j_bench_const_prop_cross_call() throws IOException, + // InterruptedException { + // Path testPath = Paths.get(root.getParent().toString(), + // "benchmarks" + File.separator + + // "issue-42-slicer4j-bench-const-prop-cross-call"); + // String jarPath = Paths + // .get(testPath.toString(), + // "target" + File.separator + // + "issue-42-slicer4j-bench-const-prop-cross-call-1.0.0.jar") + // .toString(); + + // TestUtils.buildJar(testPath); + + // Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); + // slicer.setDebug(true); + // String instrumentedJar = slicer.instrument(); + // slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", ""); + + // DynamicControlFlowGraph dcfg = slicer.prepareGraph(); + // slicer.printGraph(dcfg); + + // // Slicing criterion: ConstPropCrossCall:14 (z) + // // Idea expected slice: Lines 4, 5, 6, 7, 8, 11, 12, 13, 14. + // List tracePositions = TestUtils.getTracePositionFromSourceLine(14, + // "Bench", dcfg); + // Integer tracePositionToSliceFrom = tracePositions.isEmpty() ? 14 : + // tracePositions.get(0); + + // Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, + // tracePositionToSliceFrom); + + // Set expected = new HashSet<>( + // Arrays.asList("Bench:4", "Bench:5", "Bench:6", "Bench:7", "Bench:8", + // "Bench:11", "Bench:12", "Bench:13", "Bench:14")); + + // System.out.println("=== issue_42_slicer4j_bench_const_prop_cross_call ==="); + // System.out.println("Expected slice: " + expected); + // System.out.println("Actual slice: " + sliceLines); + // System.out.println("====================================================="); + + // assertEquals(expected, sliceLines); + // } + + // @Test + // void issue_42_slicer4j_bench_const_prop_selective() throws IOException, + // InterruptedException { + // Path testPath = Paths.get(root.getParent().toString(), + // "benchmarks" + File.separator + + // "issue-42-slicer4j-bench-const-prop-selective"); + // String jarPath = Paths + // .get(testPath.toString(), + // "target" + File.separator + // + "issue-42-slicer4j-bench-const-prop-selective-1.0.0.jar") + // .toString(); + + // TestUtils.buildJar(testPath); + + // Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, + // sliceLogger);slicer.setDebug(true); + // String instrumentedJar = slicer + // .instrument();slicer.runInstrumentedJarFromMain(instrumentedJar,"Bench","any-arg"); + + // DynamicControlFlowGraph dcfg = slicer.prepareGraph();slicer.printGraph(dcfg); + + // // Slicing criterion: ConstPropSelective:11 (msg) + // // Idea expected slice: Lines 3, 4, 5, 6, 7, 8, 9, 10, 11. + // List tracePositions = TestUtils.getTracePositionFromSourceLine(11, + // "Bench", dcfg); + // Integer tracePositionToSliceFrom = tracePositions.isEmpty() ? 11 : + // tracePositions.get(0); + + // Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, + // tracePositionToSliceFrom); + + // Set expected = new HashSet<>( + // Arrays.asList("Bench:3", "Bench:4", "Bench:5", "Bench:6", "Bench:7", + // "Bench:8", "Bench:9", "Bench:10", "Bench:11")); + + // System.out.println("=== issue_42_slicer4j_bench_const_prop_selective + // ===");System.out.println("Expected slice: + // "+expected);System.out.println("Actual slice: + // "+sliceLines);System.out.println("===================================================="); + + // assertEquals(expected, sliceLines); + // } } diff --git a/Slicer4J/src/test/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/ProgramTests.java b/Slicer4J/src/test/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/ProgramTests.java index 3fa1784..a2f1168 100644 --- a/Slicer4J/src/test/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/ProgramTests.java +++ b/Slicer4J/src/test/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/ProgramTests.java @@ -1,6 +1,5 @@ package ca.ubc.ece.resess.slicer.dynamic.slicer4j; - import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -29,206 +28,203 @@ import ca.ubc.ece.resess.slicer.dynamic.core.graph.DynamicControlFlowGraph; import ca.ubc.ece.resess.slicer.dynamic.core.statements.StatementInstance; - public class ProgramTests { Path root = Paths.get(".").normalize().toAbsolutePath(); Path slicerPath = Paths.get(root.getParent().toString(), "scripts"); Path outDir = Paths.get(slicerPath.toString(), "testTempDir"); - Path sliceLogger = Paths.get(root.getParent().getParent().toString(), "DynamicSlicingCore" + File.separator + "DynamicSlicingLoggingClasses" + File.separator + "DynamicSlicingLogger.jar"); + Path sliceLogger = Paths.get(root.getParent().getParent().toString(), "DynamicSlicingCore" + File.separator + + "DynamicSlicingLoggingClasses" + File.separator + "DynamicSlicingLogger.jar"); boolean useSets = true; - @BeforeAll + @BeforeAll static void preCleanUp() throws IOException { TestUtils.cleanWorkingDirectory(); } - - @AfterEach + + @AfterEach void postCleanUp() throws IOException { TestUtils.cleanWorkingDirectory(); } - @Test void issue1() throws IOException, InterruptedException { Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "test-issue1"); String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "test1-issue-1.0.0.jar").toString(); TestUtils.buildJar(testPath); - - String [] args = { - "-m", - "i", - "-j", - jarPath, - "-o", - outDir.toString(), - "-sl", - outDir.toString() + File.separator + "static_log.log", - "-lc", - sliceLogger.toString() + + String[] args = { + "-m", + "i", + "-j", + jarPath, + "-o", + outDir.toString(), + "-sl", + outDir.toString() + File.separator + "static_log.log", + "-lc", + sliceLogger.toString() }; Slicer.main(args); - - ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "java -Xmx8g -cp " + outDir.toString() + File.separator + "test1-issue-1.0.0_i.jar Main | grep \"SLICING\""); + + ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "java -Xmx8g -cp " + outDir.toString() + File.separator + + "test1-issue-1.0.0_i.jar Main | grep \"SLICING\""); System.out.println(pb.command()); Process p = pb.start(); - p.waitFor(); - BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); - - BufferedWriter writer = Files.newBufferedWriter(Paths.get(outDir.toString() + File.separator + "trace.log")); - String readline; - while ((readline = reader.readLine()) != null) { - writer.write(readline); - writer.write("\n"); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + BufferedWriter writer = Files.newBufferedWriter(Paths.get(outDir.toString() + File.separator + "trace.log"))) { + String readline; + while ((readline = reader.readLine()) != null) { + writer.write(readline); + writer.write("\n"); + } } - writer.close(); - reader.close(); - - args = new String [] { - "-m", - "g", - "-j", - jarPath, - "-o", - outDir.toString(), - "-t", - outDir.toString() + File.separator + "trace.log", - "-sl", - outDir.toString() + File.separator + "static_log.log", - "-sd", - root.getParent().toString() + File.separator + "models" + File.separator + "summariesManual", - "-tw", - root.getParent().toString() + File.separator + "models" + File.separator + "EasyTaintWrapperSource.txt" + p.waitFor(); + + args = new String[] { + "-m", + "g", + "-j", + jarPath, + "-o", + outDir.toString(), + "-t", + outDir.toString() + File.separator + "trace.log", + "-sl", + outDir.toString() + File.separator + "static_log.log", + "-sd", + root.getParent().toString() + File.separator + "models" + File.separator + "summariesManual", + "-tw", + root.getParent().toString() + File.separator + "models" + File.separator + "EasyTaintWrapperSource.txt" }; Slicer.main(args); - - args = new String [] { - "-m", - "s", - "-j", - jarPath, - "-o", - outDir.toString(), - "-t", - outDir.toString() + File.separator + "trace.log", - "-sl", - outDir.toString() + File.separator + "static_log.log", - "-sd", - root.getParent().toString() + File.separator + "models" + File.separator + "summariesManual", - "-tw", - root.getParent().toString() + File.separator + "models" + File.separator + "EasyTaintWrapperSource.txt", - "-sp", - "15", + + args = new String[] { + "-m", + "s", + "-j", + jarPath, + "-o", + outDir.toString(), + "-t", + outDir.toString() + File.separator + "trace.log", + "-sl", + outDir.toString() + File.separator + "static_log.log", + "-sd", + root.getParent().toString() + File.separator + "models" + File.separator + "summariesManual", + "-tw", + root.getParent().toString() + File.separator + "models" + File.separator + "EasyTaintWrapperSource.txt", + "-sp", + "15", "-d" }; Slicer.main(args); - + Path outputPath = Paths.get(slicerPath.toString(), "testTempDir" + File.separator + "slice.log"); List out = Files.readAllLines(outputPath); System.out.println(out); - if(useSets){ + if (useSets) { assertEquals(new HashSet<>(Arrays.asList( - "Main:6", - "Main:7", - "Main:17", - "Main:18", - "Main:8", - "Main:13", - "Main:9")), + "Main:6", + "Main:7", + "Main:17", + "Main:18", + "Main:8", + "Main:13", + "Main:9")), new HashSet<>(out)); } else { assertEquals(Arrays.asList( - "Main:6", - "Main:7", - "Main:17", - "Main:18", - "Main:8", - "Main:13", - "Main:9"), - out); + "Main:6", + "Main:7", + "Main:17", + "Main:18", + "Main:8", + "Main:13", + "Main:9"), + out); } } - + @Test void issue2() throws IOException, InterruptedException { Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "test-issue2"); String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "test2-issue-1.0.0.jar").toString(); TestUtils.buildJar(testPath); - - String [] args = { - "-m", - "i", - "-j", - jarPath, - "-o", - outDir.toString(), - "-sl", - outDir.toString() + File.separator + "static_log.log", - "-lc", - sliceLogger.toString() + + String[] args = { + "-m", + "i", + "-j", + jarPath, + "-o", + outDir.toString(), + "-sl", + outDir.toString() + File.separator + "static_log.log", + "-lc", + sliceLogger.toString() }; Slicer.main(args); - - ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "java -Xmx8g -cp " + outDir.toString() + File.separator + "test2-issue-1.0.0_i.jar Main something | grep \"SLICING\""); + + ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "java -Xmx8g -cp " + outDir.toString() + File.separator + + "test2-issue-1.0.0_i.jar Main something | grep \"SLICING\""); System.out.println(pb.command()); Process p = pb.start(); - p.waitFor(); - BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); - - BufferedWriter writer = Files.newBufferedWriter(Paths.get(outDir.toString() + File.separator + "trace.log")); - String readline; - while ((readline = reader.readLine()) != null) { - writer.write(readline); - writer.write("\n"); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + BufferedWriter writer = Files.newBufferedWriter(Paths.get(outDir.toString() + File.separator + "trace.log"))) { + String readline; + while ((readline = reader.readLine()) != null) { + writer.write(readline); + writer.write("\n"); + } } - writer.close(); - reader.close(); - - args = new String [] { - "-m", - "g", - "-j", - jarPath, - "-o", - outDir.toString(), - "-t", - outDir.toString() + File.separator + "trace.log", - "-sl", - outDir.toString() + File.separator + "static_log.log", - "-sd", - root.getParent().toString() + File.separator + "models" + File.separator + "summariesManual", - "-tw", - root.getParent().toString() + File.separator + "models" + File.separator + "EasyTaintWrapperSource.txt" + p.waitFor(); + + args = new String[] { + "-m", + "g", + "-j", + jarPath, + "-o", + outDir.toString(), + "-t", + outDir.toString() + File.separator + "trace.log", + "-sl", + outDir.toString() + File.separator + "static_log.log", + "-sd", + root.getParent().toString() + File.separator + "models" + File.separator + "summariesManual", + "-tw", + root.getParent().toString() + File.separator + "models" + File.separator + "EasyTaintWrapperSource.txt" }; Slicer.main(args); - - args = new String [] { - "-m", - "s", - "-j", - jarPath, - "-o", - outDir.toString(), - "-t", - outDir.toString() + File.separator + "trace.log", - "-sl", - outDir.toString() + File.separator + "static_log.log", - "-sd", - root.getParent().toString() + File.separator + "models" + File.separator + "summariesManual", - "-tw", - root.getParent().toString() + File.separator + "models" + File.separator + "EasyTaintWrapperSource.txt", - "-sp", - "16", + + args = new String[] { + "-m", + "s", + "-j", + jarPath, + "-o", + outDir.toString(), + "-t", + outDir.toString() + File.separator + "trace.log", + "-sl", + outDir.toString() + File.separator + "static_log.log", + "-sd", + root.getParent().toString() + File.separator + "models" + File.separator + "summariesManual", + "-tw", + root.getParent().toString() + File.separator + "models" + File.separator + "EasyTaintWrapperSource.txt", + "-sp", + "16", "-d" }; Slicer.main(args); - + Path outputPath = Paths.get(slicerPath.toString(), "testTempDir" + File.separator + "slice.log"); List out = Files.readAllLines(outputPath); System.out.println(out); - - if(useSets){ + + if (useSets) { assertEquals(new HashSet<>(Arrays.asList( "Main:6", "Main:15", @@ -240,171 +236,169 @@ void issue2() throws IOException, InterruptedException { new HashSet<>(out)); } else { assertEquals(Arrays.asList( - "Main:6", - "Main:15", - "Main:16", - "Main:19", - "Main:8", - "Main:9", - "Main:11"), + "Main:6", + "Main:15", + "Main:16", + "Main:19", + "Main:8", + "Main:9", + "Main:11"), out); } } - - + @Test void sliceOnce() throws IOException, InterruptedException { Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "test-issue1"); String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "test1-issue-1.0.0.jar").toString(); TestUtils.buildJar(testPath); - - String [] args = { - "-m", - "i", - "-j", - jarPath, - "-o", - outDir.toString(), - "-sl", - outDir.toString() + File.separator + "static_log.log", - "-lc", - sliceLogger.toString() + + String[] args = { + "-m", + "i", + "-j", + jarPath, + "-o", + outDir.toString(), + "-sl", + outDir.toString() + File.separator + "static_log.log", + "-lc", + sliceLogger.toString() }; Slicer.main(args); - - ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "java -Xmx8g -cp " + outDir.toString() + File.separator + "test1-issue-1.0.0_i.jar Main | grep \"SLICING\""); + + ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", "java -Xmx8g -cp " + outDir.toString() + File.separator + + "test1-issue-1.0.0_i.jar Main | grep \"SLICING\""); System.out.println(pb.command()); Process p = pb.start(); - p.waitFor(); - BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); - - BufferedWriter writer = Files.newBufferedWriter(Paths.get(outDir.toString() + File.separator + "trace.log")); - String readline; - while ((readline = reader.readLine()) != null) { - writer.write(readline); - writer.write("\n"); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + BufferedWriter writer = Files.newBufferedWriter(Paths.get(outDir.toString() + File.separator + "trace.log"))) { + String readline; + while ((readline = reader.readLine()) != null) { + writer.write(readline); + writer.write("\n"); + } } - writer.close(); - reader.close(); - - args = new String [] { - "-m", - "g", - "-j", - jarPath, - "-o", - outDir.toString(), - "-t", - outDir.toString() + File.separator + "trace.log", - "-sl", - outDir.toString() + File.separator + "static_log.log", - "-sd", - root.getParent().toString() + File.separator + "models" + File.separator + "summariesManual", - "-tw", - root.getParent().toString() + File.separator + "models" + File.separator + "EasyTaintWrapperSource.txt" + p.waitFor(); + + args = new String[] { + "-m", + "g", + "-j", + jarPath, + "-o", + outDir.toString(), + "-t", + outDir.toString() + File.separator + "trace.log", + "-sl", + outDir.toString() + File.separator + "static_log.log", + "-sd", + root.getParent().toString() + File.separator + "models" + File.separator + "summariesManual", + "-tw", + root.getParent().toString() + File.separator + "models" + File.separator + "EasyTaintWrapperSource.txt" }; Slicer.main(args); - - args = new String [] { - "-m", - "s", - "-j", - jarPath, - "-o", - outDir.toString(), - "-t", - outDir.toString() + File.separator + "trace.log", - "-sl", - outDir.toString() + File.separator + "static_log.log", - "-sd", - root.getParent().toString() + File.separator + "models" + File.separator + "summariesManual", - "-tw", - root.getParent().toString() + File.separator + "models" + File.separator + "EasyTaintWrapperSource.txt", - "-sp", - "15", - "-once" + + args = new String[] { + "-m", + "s", + "-j", + jarPath, + "-o", + outDir.toString(), + "-t", + outDir.toString() + File.separator + "trace.log", + "-sl", + outDir.toString() + File.separator + "static_log.log", + "-sd", + root.getParent().toString() + File.separator + "models" + File.separator + "summariesManual", + "-tw", + root.getParent().toString() + File.separator + "models" + File.separator + "EasyTaintWrapperSource.txt", + "-sp", + "15", + "-once" }; Slicer.main(args); - + Path outputPath = Paths.get(slicerPath.toString(), "testTempDir" + File.separator + "slice.log"); List out = Files.readAllLines(outputPath); System.out.println(out); - - if(useSets){ + + if (useSets) { assertEquals(new HashSet<>(Arrays.asList( "Main:13", "Main:9")), new HashSet<>(out)); } else { assertEquals(Arrays.asList( - "Main:13", - "Main:9"), + "Main:13", + "Main:9"), out); } } - @Test void issue5() throws IOException, InterruptedException { Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "test-issue5"); String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "test-issue5-1.0.0.jar").toString(); - + TestUtils.buildJar(testPath); - + Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); slicer.setDebug(true); String instrumentedJar = slicer.instrument(); slicer.runInstrumentedJarFromMain(instrumentedJar, "TreeAdd", "-l 2"); - + DynamicControlFlowGraph dcfg = slicer.prepareGraph(); slicer.printGraph(dcfg); - + Integer tracePositionToSliceFrom = 107; Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); Set expected = new HashSet<>(Arrays.asList( - "TreeAdd:68", - "TreeNode:50", - "TreeNode:102", - "TreeAdd:67", - "TreeNode:60", - "TreeNode:101", - "TreeNode:104", - "TreeAdd:36", - "TreeNode:103", - "TreeNode:106", - "TreeNode:105", - "TreeAdd:70", - "TreeAdd:62", - "TreeNode:49", - "TreeAdd:40", - "TreeAdd:72", - "TreeNode:59", - "TreeAdd:53", - "TreeAdd:33", - "TreeAdd:65")); + "TreeAdd:68", + "TreeNode:50", + "TreeNode:102", + "TreeAdd:67", + "TreeNode:60", + "TreeNode:101", + "TreeNode:104", + "TreeAdd:36", + "TreeNode:103", + "TreeNode:106", + "TreeNode:105", + "TreeAdd:70", + "TreeAdd:62", + "TreeNode:49", + "TreeAdd:40", + "TreeAdd:72", + "TreeNode:59", + "TreeAdd:53", + "TreeAdd:33", + "TreeAdd:65")); Assertions.assertTrue(sliceLines.containsAll(expected)); } - + @Test void directStatementDependency() throws IOException, InterruptedException { Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "test-issue1"); String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "test1-issue-1.0.0.jar").toString(); - + TestUtils.buildJar(testPath); - + Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); - + String instrumentedJar = slicer.instrument(); slicer.runInstrumentedJarFromMain(instrumentedJar, "Main", ""); - + DynamicControlFlowGraph dcfg = slicer.prepareGraph(); slicer.printGraph(dcfg); - + Integer tracePositionToSliceFrom = 15; - Map slideDeps = TestUtils.sliceAndGetDirectDepdendeincesMap(slicer, dcfg, tracePositionToSliceFrom); - + Map slideDeps = TestUtils.sliceAndGetDirectDepdendeincesMap(slicer, dcfg, + tracePositionToSliceFrom); + Map expected = new HashMap<>(); expected.put(dcfg.mapNoUnits(15), "start"); expected.put(dcfg.mapNoUnits(14), "data, varaible:stack5, source:15"); @@ -414,119 +408,117 @@ void directStatementDependency() throws IOException, InterruptedException { assertEquals(expected, slideDeps); } - @Test void testFieldsFramework() throws IOException, InterruptedException { Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "test-fields-framework"); - String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "test-fields-framework-1.0.0.jar").toString(); - + String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "test-fields-framework-1.0.0.jar") + .toString(); + TestUtils.buildJar(testPath); - + Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); slicer.setDebug(true); String instrumentedJar = slicer.instrument(); slicer.runInstrumentedJarFromMain(instrumentedJar, "Main", ""); - + DynamicControlFlowGraph dcfg = slicer.prepareGraph(); slicer.printGraph(dcfg); - + Integer tracePositionToSliceFrom = 21; Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); Set expected = new HashSet<>(Arrays.asList( - "Main:18", - "Main:17", - "Main:9", - "Main:8", - "Main:13", - "Main:7", - "Main:5" - )); + "Main:18", + "Main:17", + "Main:9", + "Main:8", + "Main:13", + "Main:7", + "Main:5")); assertEquals(expected, sliceLines); } - @Test void issue10() throws IOException, InterruptedException { Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "test-issue10"); - String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "test-issue10-1.0.0.jar").toString(); - + String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "test-issue10-1.0.0.jar") + .toString(); + TestUtils.buildJar(testPath); - + Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); slicer.setDebug(true); String instrumentedJar = slicer.instrument(); slicer.runInstrumentedJarFromMain(instrumentedJar, "Issue", ""); - + DynamicControlFlowGraph dcfg = slicer.prepareGraph(); slicer.printGraph(dcfg); - + Integer tracePositionToSliceFrom = 10; Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); Set expected = new HashSet<>(Arrays.asList( - "Issue:10", - "Issue:9", - "Issue:6")); + "Issue:10", + "Issue:9", + "Issue:6")); assertEquals(expected, sliceLines); } - @Test void issue11() throws IOException, InterruptedException { Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "test-issue11"); - String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "test-issue11-1.0.0.jar").toString(); - + String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "test-issue11-1.0.0.jar") + .toString(); + TestUtils.buildJar(testPath); - + Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); slicer.setDebug(true); String instrumentedJar = slicer.instrument(); slicer.runInstrumentedJarFromMain(instrumentedJar, "Issue", ""); - + DynamicControlFlowGraph dcfg = slicer.prepareGraph(); slicer.printGraph(dcfg); - + Integer tracePositionToSliceFrom = 30; Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); Set expected = new HashSet<>(Arrays.asList( - "Issue:10", - "Issue:9", - "Pair:49", - "Pair:44", - "Pair:43", - "Pair:42", - "PairSet:33", - "PairSet:31", - "PairSet:30", - "PairSet:29", - "PairSet:24", - "PairSet:23", - "PairSet:19", - "PairSet:18")); + "Issue:10", + "Issue:9", + "Pair:49", + "Pair:44", + "Pair:43", + "Pair:42", + "PairSet:33", + "PairSet:31", + "PairSet:30", + "PairSet:29", + "PairSet:24", + "PairSet:23", + "PairSet:19", + "PairSet:18")); assertEquals(expected, sliceLines); } - @Test void sliceMe_test() throws IOException, InterruptedException { Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "SliceMe"); String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "SliceMe-1.0.0.jar").toString(); - + TestUtils.buildJar(testPath); - + Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); - + String instrumentedJar = slicer.instrument(); slicer.runInstrumentedJarFromMain(instrumentedJar, "SliceMe", ""); - + DynamicControlFlowGraph dcfg = slicer.prepareGraph(); slicer.printGraph(dcfg); - + Integer tracePositionToSliceFrom = 5; Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom); @@ -535,32 +527,34 @@ void sliceMe_test() throws IOException, InterruptedException { assertEquals(expected, sliceLines); } - - - @Test void conditions() throws IOException, InterruptedException { Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "test-conditions"); - String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "test-conditions-1.0.0.jar").toString(); - + String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "test-conditions-1.0.0.jar") + .toString(); + TestUtils.buildJar(testPath); - + Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); - + String instrumentedJar = slicer.instrument(); slicer.runInstrumentedJarFromMain(instrumentedJar, "Bench", ""); - + DynamicControlFlowGraph dcfg = slicer.prepareGraph(); slicer.printGraph(dcfg); - + Integer tracePositionToSliceFrom = 83; - List sliceLines = new ArrayList<>(TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom)).stream() - .sorted((a, b) -> a.compareTo(b)) - .collect(Collectors.toList()); + List sliceLines = new ArrayList<>( + TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositionToSliceFrom)).stream() + .sorted((a, b) -> a.compareTo(b)) + .collect(Collectors.toList()); - List expected = Arrays.asList("Bench:29", "Bench:26", "Bench:25", "Bench:22", "Bench:21", "Bench:17", "Bench:16", "Bench:18", "Bench:15", "Bench:10", "Bench:7", "Bench:4").stream() - .sorted((a, b) -> a.compareTo(b)) - .collect(Collectors.toList()); + List expected = Arrays + .asList("Bench:29", "Bench:26", "Bench:25", "Bench:22", "Bench:21", "Bench:17", "Bench:16", "Bench:18", + "Bench:15", "Bench:10", "Bench:7", "Bench:4") + .stream() + .sorted((a, b) -> a.compareTo(b)) + .collect(Collectors.toList()); assertEquals(expected, sliceLines); } @@ -569,21 +563,26 @@ void conditions() throws IOException, InterruptedException { void inpressDCFGAssertionTest() throws IOException, InterruptedException { // bug where last line did not have predecessors Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "inpress-case8"); - String jarPath = Paths.get(testPath.toString(), "results" + File.separator + "new" + File.separator + "program.jar").toString(); + String jarPath = Paths + .get(testPath.toString(), "results" + File.separator + "new" + File.separator + "program.jar") + .toString(); String depPath = Paths.get(testPath.toString(), "bug" + File.separator + "lib").toString(); Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); String instrumentedJar = slicer.instrument(); - TestUtils.runInstrumentedJarFromTest(instrumentedJar, depPath, "org.apache.commons.lang3.time.FastDatePrinterTest", "testCalendarTimezoneRespected", String.valueOf(outDir)); + TestUtils.runInstrumentedJarFromTest(instrumentedJar, depPath, + "org.apache.commons.lang3.time.FastDatePrinterTest", "testCalendarTimezoneRespected", + String.valueOf(outDir)); DynamicControlFlowGraph dcfg = slicer.prepareGraph(); slicer.printGraph(dcfg); assert !dcfg.predecessorListOf((int) dcfg.getLastLine()).isEmpty(); } - void runInsertionSortTest( int sourceLine, List expectedSlice ) throws IOException, InterruptedException { - Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "InsertionSort-MemSat01"); + void runInsertionSortTest(int sourceLine, List expectedSlice) throws IOException, InterruptedException { + Path testPath = Paths.get(root.getParent().toString(), + "benchmarks" + File.separator + "InsertionSort-MemSat01"); String jarPath = Paths.get(testPath.toString(), "test.jar").toString(); Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); @@ -594,12 +593,13 @@ void runInsertionSortTest( int sourceLine, List expectedSlice ) throws I DynamicControlFlowGraph dcfg = slicer.prepareGraph(); slicer.printGraph(dcfg); - List tracePositions = TestUtils.getTracePositionFromSourceLine( sourceLine, "Main", dcfg ); - List sliceLines = new ArrayList<>(TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositions)).stream() + List tracePositions = TestUtils.getTracePositionFromSourceLine(sourceLine, "Main", dcfg); + List sliceLines = new ArrayList<>(TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositions)) + .stream() .sorted((a, b) -> a.compareTo(b)) .collect(Collectors.toList()); - assertEquals( sliceLines, expectedSlice ); + assertEquals(sliceLines, expectedSlice); } @Test @@ -608,16 +608,52 @@ void svCompInsertionSort2() throws IOException, InterruptedException { .sorted((a, b) -> a.compareTo(b)) .collect(Collectors.toList()); - runInsertionSortTest( 58, expected ); + runInsertionSortTest(58, expected); } - @Test - void svCompInsertionSort3() throws IOException, InterruptedException { - List expected = Arrays.asList("Main:58", "Main:45", "Main:46", "Main:47", "Main:40", "Main:54", - "Main:41", "Main:42", "Main:62", "Main:49", "Main:56", "Main:57", "Main:39" ).stream() - .sorted((a, b) -> a.compareTo(b)) - .collect(Collectors.toList()); + // This issue is related to the modeling of println. Please see #Issue 28 for an + // explanation of why this test is commented out + // @Test + // void issue28_1() throws IOException, InterruptedException { + // Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + + // File.separator + "test-issue28-1"); + // String jarPath = Paths.get(testPath.toString(), "target" + File.separator + + // "test-issue28-1-1.0.0.jar") + // .toString(); + // TestUtils.buildJar(testPath); + // Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); + // String instrumentedJar = slicer.instrument(); + // slicer.runInstrumentedJarFromMain(instrumentedJar, "Main", ""); + // DynamicControlFlowGraph dcfg = slicer.prepareGraph(); + // slicer.printGraph(dcfg); + // List tracePositions = TestUtils.getTracePositionFromSourceLine(11, + // "Main", dcfg); + // Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, + // tracePositions); + // Set expected = new HashSet<>(Arrays.asList( + // "Main:11", + // "Main:8", + // "Main:6", + // "Main:5", + // "Main:4", + // "Main:3")); + // assertEquals(expected, sliceLines); + // } - runInsertionSortTest( 49, expected ); + @Test + void issue28_2() throws IOException, InterruptedException { + Path testPath = Paths.get(root.getParent().toString(), "benchmarks" + File.separator + "test-issue28-2"); + String jarPath = Paths.get(testPath.toString(), "target" + File.separator + "test-issue28-2-1.0.0.jar") + .toString(); + TestUtils.buildJar(testPath); + Slicer slicer = TestUtils.setupSlicing(root, jarPath, outDir, sliceLogger); + String instrumentedJar = slicer.instrument(); + slicer.runInstrumentedJarFromMain(instrumentedJar, "Main", ""); + DynamicControlFlowGraph dcfg = slicer.prepareGraph(); + slicer.printGraph(dcfg); + List tracePositions = TestUtils.getTracePositionFromSourceLine(6, "Main", dcfg); + Set sliceLines = TestUtils.sliceAndGetSourceLines(slicer, dcfg, tracePositions); + Assertions.assertFalse(sliceLines.contains("Main:3")); + Assertions.assertFalse(sliceLines.contains("Main:4")); } } diff --git a/Slicer4J/src/test/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/TestUtils.java b/Slicer4J/src/test/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/TestUtils.java index 4b6a1a9..2c5cc09 100644 --- a/Slicer4J/src/test/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/TestUtils.java +++ b/Slicer4J/src/test/java/ca/ubc/ece/resess/slicer/dynamic/slicer4j/TestUtils.java @@ -58,37 +58,30 @@ public static void runInstrumentedJarFromTest(String pathToJar, String dependenc testClass + "#" + testMethod; ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", cmd + "| grep \"SLICING\""); Process p = pb.start(); - p.waitFor(); - BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); - BufferedWriter writer = Files.newBufferedWriter(Paths.get(outDir + File.separator + "trace.log")); - String readline; - while ((readline = reader.readLine()) != null) { - writer.write(readline); - writer.write("\n"); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + BufferedWriter writer = Files.newBufferedWriter(Paths.get(outDir + File.separator + "trace.log"))) { + String readline; + while ((readline = reader.readLine()) != null) { + writer.write(readline); + writer.write("\n"); + } } - writer.close(); - reader.close(); + p.waitFor(); } protected static void buildJar(Path testPath) throws IOException, InterruptedException { - Process p = null; ProcessBuilder pb = new ProcessBuilder("mvn", "clean", "package"); pb.directory(testPath.toFile()); - p = pb.start(); - p.waitFor(); - System.out.println("Out stream: "); - BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); - String readline; - while ((readline = reader.readLine()) != null) { - System.out.println(readline); - } - reader.close(); - System.out.println("Error stream: "); - reader = new BufferedReader(new InputStreamReader(p.getErrorStream())); - while ((readline = reader.readLine()) != null) { - System.out.println(readline); + pb.redirectErrorStream(true); + Process p = pb.start(); + + try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()))) { + String readline; + while ((readline = reader.readLine()) != null) { + System.out.println(readline); + } } - reader.close(); + p.waitFor(); } protected static void cleanWorkingDirectory() throws IOException { diff --git a/benchmarks/Gson_4b/gson/pom.xml b/benchmarks/Gson_4b/gson/pom.xml index 99b17d3..5e89de8 100644 --- a/benchmarks/Gson_4b/gson/pom.xml +++ b/benchmarks/Gson_4b/gson/pom.xml @@ -113,8 +113,8 @@ maven-compiler-plugin 3.3 - 1.6 - 1.6 + 1.7 + 1.7 diff --git a/benchmarks/JacksonCore_4b/pom.xml b/benchmarks/JacksonCore_4b/pom.xml index 748e7d6..2c195c3 100644 --- a/benchmarks/JacksonCore_4b/pom.xml +++ b/benchmarks/JacksonCore_4b/pom.xml @@ -1,5 +1,5 @@ - 4.0.0 + 4.0.0 com.fasterxml.jackson jackson-parent @@ -18,7 +18,7 @@ scm:git:git@github.com:FasterXML/jackson-core.git scm:git:git@github.com:FasterXML/jackson-core.git - http://github.com/FasterXML/jackson-core + http://github.com/FasterXML/jackson-core HEAD @@ -34,6 +34,17 @@ com.fasterxml.jackson.core.*;version=${project.version} + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.7 + 1.7 + true + lines,vars,source + + org.apache.maven.plugins maven-javadoc-plugin @@ -83,7 +94,7 @@ com.fasterxml.jackson.core.*;version=${project.version} 2.8.1 true - 1.6 + 1.7 UTF-8 1g diff --git a/benchmarks/JacksonDatabind_3b/pom.xml b/benchmarks/JacksonDatabind_3b/pom.xml index fd0177a..7a597ad 100644 --- a/benchmarks/JacksonDatabind_3b/pom.xml +++ b/benchmarks/JacksonDatabind_3b/pom.xml @@ -101,7 +101,18 @@ javax.xml.datatype, javax.xml.namespace, javax.xml.parsers - + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.7 + 1.7 + true + lines,vars,source + + org.apache.maven.plugins maven-release-plugin diff --git a/benchmarks/JacksonDatabind_3b/src/main/java/com/fasterxml/jackson/databind/module/SimpleModule.java b/benchmarks/JacksonDatabind_3b/src/main/java/com/fasterxml/jackson/databind/module/SimpleModule.java index 6a33afb..a283592 100644 --- a/benchmarks/JacksonDatabind_3b/src/main/java/com/fasterxml/jackson/databind/module/SimpleModule.java +++ b/benchmarks/JacksonDatabind_3b/src/main/java/com/fasterxml/jackson/databind/module/SimpleModule.java @@ -27,7 +27,7 @@ * to ensure that registration works as expected. */ public class SimpleModule - extends Module + extends com.fasterxml.jackson.databind.Module implements java.io.Serializable { // at 2.4.0: @@ -35,7 +35,7 @@ public class SimpleModule protected final String _name; protected final Version _version; - + protected SimpleSerializers _serializers = null; protected SimpleDeserializers _deserializers = null; @@ -71,7 +71,7 @@ public class SimpleModule * by target class, value being mix-in to apply. */ protected HashMap, Class> _mixins = null; - + /** * Set of subtypes to register, if any. */ @@ -81,7 +81,7 @@ public class SimpleModule * @since 2.3 */ protected PropertyNamingStrategy _namingStrategy = null; - + /* /********************************************************** /* Life-cycle: creation @@ -98,7 +98,7 @@ public SimpleModule() { _name = "SimpleModule-"+System.identityHashCode(this); _version = Version.unknownVersion(); } - + /** * Convenience constructor that will default version to * {@link Version#unknownVersion()}. @@ -115,13 +115,13 @@ public SimpleModule(Version version) { _name = version.getArtifactId(); _version = version; } - + /** * Constructor to use for actual reusable modules. * ObjectMapper may use name as identifier to notice attempts * for multiple registrations of the same module (although it * does not have to). - * + * * @param name Unique name of the module * @param version Version of the module */ @@ -145,7 +145,7 @@ public SimpleModule(String name, Version version, List> serializers) { this(name, version, null, serializers); } - + /** * @since 2.1 */ @@ -162,7 +162,7 @@ public SimpleModule(String name, Version version, _serializers = new SimpleSerializers(serializers); } } - + /* /********************************************************** /* Simple setters to allow overriding @@ -201,7 +201,7 @@ public void setKeyDeserializers(SimpleKeyDeserializers kd) { * Resets currently configured abstract type mappings */ public void setAbstractTypes(SimpleAbstractTypeResolver atr) { - _abstractTypes = atr; + _abstractTypes = atr; } /** @@ -234,13 +234,13 @@ protected SimpleModule setNamingStrategy(PropertyNamingStrategy naming) { _namingStrategy = naming; return this; } - + /* /********************************************************** /* Configuration methods /********************************************************** */ - + public SimpleModule addSerializer(JsonSerializer ser) { if (_serializers == null) { @@ -249,7 +249,7 @@ public SimpleModule addSerializer(JsonSerializer ser) _serializers.addSerializer(ser); return this; } - + public SimpleModule addSerializer(Class type, JsonSerializer ser) { if (_serializers == null) { @@ -267,7 +267,7 @@ public SimpleModule addKeySerializer(Class type, JsonSerializer _keySerializers.addSerializer(type, ser); return this; } - + public SimpleModule addDeserializer(Class type, JsonDeserializer deser) { if (_deserializers == null) { @@ -349,7 +349,7 @@ public SimpleModule registerSubtypes(NamedType ... subtypes) } return this; } - + /** * Method for specifying that annotations define by mixinClass * should be "mixed in" with annotations that targetType @@ -366,13 +366,13 @@ public SimpleModule setMixInAnnotation(Class targetType, Class mixinClass) _mixins.put(targetType, mixinClass); return this; } - + /* /********************************************************** /* Module impl /********************************************************** */ - + @Override public String getModuleName() { return _name; @@ -380,7 +380,7 @@ public String getModuleName() { /** * Standard implementation handles registration of all configured - * customizations: it is important that sub-classes call this + * customizations: it is important that sub-classes call this * implementation (usually before additional custom logic) * if they choose to override it; otherwise customizations * will not be registered. diff --git a/benchmarks/JacksonDatabind_3b/src/test/java/com/fasterxml/jackson/databind/creators/TestCreatorNullValue.java b/benchmarks/JacksonDatabind_3b/src/test/java/com/fasterxml/jackson/databind/creators/TestCreatorNullValue.java index 34e084d..7a504aa 100644 --- a/benchmarks/JacksonDatabind_3b/src/test/java/com/fasterxml/jackson/databind/creators/TestCreatorNullValue.java +++ b/benchmarks/JacksonDatabind_3b/src/test/java/com/fasterxml/jackson/databind/creators/TestCreatorNullValue.java @@ -51,7 +51,7 @@ public JsonDeserializer findBeanDeserializer(JavaType type, } } - private static class TestModule extends Module + private static class TestModule extends com.fasterxml.jackson.databind.Module { @Override public String getModuleName() { @@ -74,7 +74,7 @@ public void setupModule(SetupContext setupContext) { /* Unit tests /********************************************************** */ - + public void testUsesDeserializersNullValue() throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new TestModule()); diff --git a/benchmarks/JacksonDatabind_3b/src/test/java/com/fasterxml/jackson/databind/module/TestSimpleModule.java b/benchmarks/JacksonDatabind_3b/src/test/java/com/fasterxml/jackson/databind/module/TestSimpleModule.java index 96f0840..cf2e2ac 100644 --- a/benchmarks/JacksonDatabind_3b/src/test/java/com/fasterxml/jackson/databind/module/TestSimpleModule.java +++ b/benchmarks/JacksonDatabind_3b/src/test/java/com/fasterxml/jackson/databind/module/TestSimpleModule.java @@ -22,7 +22,7 @@ public class TestSimpleModule extends BaseMapTest /* Helper classes; simple beans and their handlers /********************************************************** */ - + /** * Trivial bean that requires custom serializer and deserializer */ @@ -30,7 +30,7 @@ final static class CustomBean { protected String str; protected int num; - + public CustomBean(String s, int i) { str = s; num = i; @@ -38,7 +38,7 @@ public CustomBean(String s, int i) { } static enum SimpleEnum { A, B; } - + // Extend SerializerBase to get access to declared handledType static class CustomBeanSerializer extends StdSerializer { @@ -57,7 +57,7 @@ public JsonNode getSchema(SerializerProvider provider, Type typeHint) throws Jso return null; } } - + static class CustomBeanDeserializer extends JsonDeserializer { @Override @@ -105,7 +105,7 @@ public SimpleEnum deserialize(JsonParser jp, DeserializationContext ctxt) interface Base { public String getText(); } - + static class Impl1 implements Base { @Override public String getText() { return "1"; } @@ -119,7 +119,7 @@ static class Impl2 extends Impl1 { static class BaseSerializer extends StdScalarSerializer { public BaseSerializer() { super(Base.class); } - + @Override public void serialize(Base value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeString("Base:"+value.getText()); @@ -134,7 +134,7 @@ static class MixableBean { @JsonPropertyOrder({"c", "a", "b"}) static class MixInForOrder { } - + protected static class MySimpleSerializers extends SimpleSerializers { } protected static class MySimpleDeserializers extends SimpleDeserializers { } @@ -151,7 +151,7 @@ public MySimpleModule(String name, Version version) { } } - protected static class ContextVerifierModule extends Module + protected static class ContextVerifierModule extends com.fasterxml.jackson.databind.Module { @Override public String getModuleName() { return "x"; } @@ -169,7 +169,7 @@ public void setupModule(SetupContext context) assertNotNull(m); } } - + /* /********************************************************** /* Unit tests; first, verifying need for custom handlers @@ -199,13 +199,13 @@ public void testWithoutModule() verifyException(e, "No suitable constructor found"); } } - + /* /********************************************************** /* Unit tests; simple serializers /********************************************************** */ - + public void testSimpleBeanSerializer() throws Exception { ObjectMapper mapper = new ObjectMapper(); @@ -234,13 +234,13 @@ public void testSimpleInterfaceSerializer() throws Exception assertEquals(quote("Base:1"), mapper.writeValueAsString(new Impl1())); assertEquals(quote("Base:2"), mapper.writeValueAsString(new Impl2())); } - + /* /********************************************************** /* Unit tests; simple deserializers /********************************************************** */ - + public void testSimpleBeanDeserializer() throws Exception { ObjectMapper mapper = new ObjectMapper(); @@ -261,7 +261,7 @@ public void testSimpleEnumDeserializer() throws Exception SimpleEnum result = mapper.readValue(quote("a"), SimpleEnum.class); assertSame(SimpleEnum.A, result); } - + // Simple verification of [JACKSON-455] public void testMultipleModules() throws Exception { @@ -293,7 +293,7 @@ public void testMultipleModules() throws Exception /* Unit tests; other /********************************************************** */ - + // [JACKSON-644]: ability to register mix-ins public void testMixIns() throws Exception { @@ -311,7 +311,7 @@ public void testMixIns() throws Exception // [JACKSON-686] public void testAccessToMapper() throws Exception { - ContextVerifierModule module = new ContextVerifierModule(); + ContextVerifierModule module = new ContextVerifierModule(); ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(module); } diff --git a/benchmarks/SliceMe/pom.xml b/benchmarks/SliceMe/pom.xml index 1bab152..81a0df0 100644 --- a/benchmarks/SliceMe/pom.xml +++ b/benchmarks/SliceMe/pom.xml @@ -15,8 +15,8 @@ maven-compiler-plugin 3.8.1 - 1.6 - 1.6 + 1.7 + 1.7 diff --git a/benchmarks/benchmarks_compare.py b/benchmarks/benchmarks_compare.py index 6bb91b3..696fa0c 100644 --- a/benchmarks/benchmarks_compare.py +++ b/benchmarks/benchmarks_compare.py @@ -16,7 +16,7 @@ "javaslicer-bench1-intra-procedural" : ("target/javaslicer-bench1-intra-procedural-1.0.0.jar", "Bench 2 ", "Bench", 8), "javaslicer-bench2-inter-procedural" : ("target/javaslicer-bench2-inter-procedural-1.0.0.jar", "Bench 2 4 ", "Bench", 8), "javaslicer-bench3-exceptions" : ("target/javaslicer-bench3-exceptions-1.0.0.jar", "Bench ", "Bench", 29), - "slicer4j-bench1-multiple-threads": ("target/slicer4j-bench1-multiple-threads-1.0.0.jar", "Bench ", "Bench", 14), + "slicer4j-bench1-multiple-threads": ("target/slicer4j-bench1-multiple-threads-1.0.0.jar", "Bench ", "Bench", 14), "slicer4j-bench2-native-framework": ("target/slicer4j-bench2-native-framework-1.0.0.jar", "Bench 0 4", "Bench", 9), "slicer4j-bench3-java-9-constructs": ("target/slicer4j-bench3-java-9-constructs-1.0.0.jar", "Bench 3 4", "Bench", 9), "slicer4j-bench4-instrumentation-classes": ("target/slicer4j-bench4-instrumentation-classes-1.0.0.jar", "Bench 22 ", "Bench", 10), @@ -25,8 +25,8 @@ defects4j_benchmarks = { "JacksonDatabind_3b": ("target/jackson-databind-2.4.1-SNAPSHOT.jar", "org.junit.runner.JUnitCore com.fasterxml.jackson.databind.deser.TestArrayDeserialization", "com.fasterxml.jackson.databind.ObjectMapper", "3062", "_readMapAndClose", "JacksonDatabind_3b/target/test-classes/:JacksonDatabind_3b/target/dependency/*"), - "Gson_4b": ("gson/target/gson-2.6-SNAPSHOT.jar", "junit.textui.TestRunner com.google.gson.stream.JsonReaderTest", "com.google.gson.stream.JsonReader", "1422", "checkLenient", "Gson_4b/gson/target/test-classes/:Gson_4b/gson/target/dependency/*"), - "JacksonCore_4b": ("target/jackson-core-2.5.0-SNAPSHOT.jar", "org.junit.runner.JUnitCore com.fasterxml.jackson.core.util.TestTextBuffer", "com.fasterxml.jackson.core.util.TextBuffer", "587", "expandCurrentSegment", "JacksonCore_4b/target/test-classes/:JacksonCore_4b/target/dependency/*"), + "Gson_4b": ("gson/target/gson-2.6-SNAPSHOT.jar", "junit.textui.TestRunner com.google.gson.stream.JsonReaderTest", "com.google.gson.stream.JsonReader", "1422", "checkLenient", "Gson_4b/gson/target/test-classes/:Gson_4b/gson/target/dependency/*"), + "JacksonCore_4b": ("target/jackson-core-2.5.0-SNAPSHOT.jar", "org.junit.runner.JUnitCore com.fasterxml.jackson.core.util.TestTextBuffer", "com.fasterxml.jackson.core.util.TextBuffer", "587", "expandCurrentSegment", "JacksonCore_4b/target/test-classes/:JacksonCore_4b/target/dependency/*"), } analysis = open("js-vs-slc4j.csv","w") @@ -141,7 +141,9 @@ def run_slicer4jold(project, jar_name, project_arg, extra_libs, sc_file, slice_l print(f"looking for LINENO:{slice_line}:FILE:{sc_file}") with open(f"{out_dir}/trace.log_icdg.log", 'r') as f: for l in f: - if f"LINENO:{slice_line}:FILE:{sc_file}" in l: + if "goto [" in l: + pass + elif f"LINENO:{slice_line}:FILE:{sc_file}" in l: sc = l.rstrip() line = sc.split(", ")[0] slice_cmd = f"java -Xmx8g -cp \"{slicer4j_dir}/target/slicer4j_old.jar:{slicer4j_dir}/target/lib/*\" ca.ubc.ece.resess.slicer.dynamic.slicer4j.Slicer -j {jar_name} -m s -t {out_dir}/trace.log -o {out_dir}/ -sl {out_dir}/static-log.log -sd {slicer4j_dir}/../models/summariesManual -tw {slicer4j_dir}/../models/EasyTaintWrapperSource.txt -sp {line} > {out_dir}/{slice_file}_{line}.log 2>&1" @@ -198,7 +200,9 @@ def run_slicer4jnew(project, jar_name, project_arg, extra_libs, sc_file, slice_l print(f"looking for LINENO:{slice_line}:FILE:{sc_file}") with open(f"{out_dir}/trace.log_icdg.log", 'r') as f: for l in f: - if f"LINENO:{slice_line}:FILE:{sc_file}" in l: + if "goto [" in l: + pass + elif f"LINENO:{slice_line}:FILE:{sc_file}" in l: sc = l.rstrip() line = sc.split(", ")[0] slice_cmd = f"java -Xmx8g -cp \"{slicer4j_dir}/target/slicer4j_new.jar:{slicer4j_dir}/target/lib/*\" ca.ubc.ece.resess.slicer.dynamic.slicer4j.Slicer -j {jar_name} -m s -t {out_dir}/trace.log -o {out_dir}/ -sl {out_dir}/static-log.log -sd {slicer4j_dir}/../models/summariesManual -tw {slicer4j_dir}/../models/EasyTaintWrapperSource.txt -sp {line} -noprint > {out_dir}/{slice_file}_{line}.log 2>&1" diff --git a/benchmarks/issue-42-slicer4j-bench-const-prop-cross-call/pom.xml b/benchmarks/issue-42-slicer4j-bench-const-prop-cross-call/pom.xml new file mode 100644 index 0000000..f76842e --- /dev/null +++ b/benchmarks/issue-42-slicer4j-bench-const-prop-cross-call/pom.xml @@ -0,0 +1,26 @@ + + + + 4.0.0 + slicer4j + issue-42-slicer4j-bench-const-prop-cross-call + 1.0.0 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + true + lines,vars,source + + + + + + diff --git a/benchmarks/issue-42-slicer4j-bench-const-prop-cross-call/src/main/java/Bench.java b/benchmarks/issue-42-slicer4j-bench-const-prop-cross-call/src/main/java/Bench.java new file mode 100644 index 0000000..77571ab --- /dev/null +++ b/benchmarks/issue-42-slicer4j-bench-const-prop-cross-call/src/main/java/Bench.java @@ -0,0 +1,17 @@ +public class Bench { + + static int compute(int start, int end, int seed) { + int gap = end - start; // line 4 + int offset = start + 1; // line 5 + int base = gap * 2; // line 6 + int result = base + offset + seed; // line 7 + return result; // line 8 + } + + public static void main(String[] args) { + int x = 5; // line 11 + int y = 15; // line 12 + int z = compute(x, y, 3); // line 13 + System.out.println(z); // line 14 + } +} diff --git a/benchmarks/issue-42-slicer4j-bench-const-prop-selective/pom.xml b/benchmarks/issue-42-slicer4j-bench-const-prop-selective/pom.xml new file mode 100644 index 0000000..71ba813 --- /dev/null +++ b/benchmarks/issue-42-slicer4j-bench-const-prop-selective/pom.xml @@ -0,0 +1,26 @@ + + + + 4.0.0 + slicer4j + issue-42-slicer4j-bench-const-prop-selective + 1.0.0 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + true + lines,vars,source + + + + + + diff --git a/benchmarks/issue-42-slicer4j-bench-const-prop-selective/src/main/java/Bench.java b/benchmarks/issue-42-slicer4j-bench-const-prop-selective/src/main/java/Bench.java new file mode 100644 index 0000000..fbe9cee --- /dev/null +++ b/benchmarks/issue-42-slicer4j-bench-const-prop-selective/src/main/java/Bench.java @@ -0,0 +1,13 @@ +public class Bench { + public static void main(String[] args) { + int MAGIC = 42; // line 3 + int FACTOR = 3; // line 4 + int dynamic = args.length; // line 5 + int mixed = MAGIC + dynamic; // line 6 + int step1 = mixed * FACTOR; // line 7 + int step2 = step1 + MAGIC; // line 8 + int step3 = step2 - dynamic; // line 9 + String msg = "Result=" + step3; // line 10 + System.out.println(msg); // line 11 + } +} diff --git a/benchmarks/issue-42-slicer4j-bench-const-prop-simple/pom.xml b/benchmarks/issue-42-slicer4j-bench-const-prop-simple/pom.xml new file mode 100644 index 0000000..fc0db18 --- /dev/null +++ b/benchmarks/issue-42-slicer4j-bench-const-prop-simple/pom.xml @@ -0,0 +1,26 @@ + + + + 4.0.0 + slicer4j + issue-42-slicer4j-bench-const-prop-simple + 1.0.0 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + true + lines,vars,source + + + + + + diff --git a/benchmarks/issue-42-slicer4j-bench-const-prop-simple/src/main/java/Bench.java b/benchmarks/issue-42-slicer4j-bench-const-prop-simple/src/main/java/Bench.java new file mode 100644 index 0000000..40afa60 --- /dev/null +++ b/benchmarks/issue-42-slicer4j-bench-const-prop-simple/src/main/java/Bench.java @@ -0,0 +1,9 @@ +public class Bench { + public static void main(String[] args) { + int b = 2; // line 3 + int a = 1 + b; // line 4 + int c = a * 3; // line 5 + int d = c + 10; // line 6 + System.out.println(d); // line 7 + } +} diff --git a/benchmarks/javaslicer-bench1-intra-procedural/pom.xml b/benchmarks/javaslicer-bench1-intra-procedural/pom.xml index 9be6808..c033263 100644 --- a/benchmarks/javaslicer-bench1-intra-procedural/pom.xml +++ b/benchmarks/javaslicer-bench1-intra-procedural/pom.xml @@ -14,10 +14,10 @@ maven-compiler-plugin 3.8.1 - 1.6 - 1.6 + 1.7 + 1.7 true - lines,vars,source + lines,vars,source diff --git a/benchmarks/javaslicer-bench2-inter-procedural/pom.xml b/benchmarks/javaslicer-bench2-inter-procedural/pom.xml index ec86d11..6e74678 100644 --- a/benchmarks/javaslicer-bench2-inter-procedural/pom.xml +++ b/benchmarks/javaslicer-bench2-inter-procedural/pom.xml @@ -14,10 +14,10 @@ maven-compiler-plugin 3.8.1 - 1.6 - 1.6 + 1.7 + 1.7 true - lines,vars,source + lines,vars,source diff --git a/benchmarks/javaslicer-bench3-exceptions/pom.xml b/benchmarks/javaslicer-bench3-exceptions/pom.xml index 058d3b3..e1fe777 100644 --- a/benchmarks/javaslicer-bench3-exceptions/pom.xml +++ b/benchmarks/javaslicer-bench3-exceptions/pom.xml @@ -14,10 +14,10 @@ maven-compiler-plugin 3.8.1 - 1.6 - 1.6 + 1.7 + 1.7 true - lines,vars,source + lines,vars,source diff --git a/benchmarks/run_benchmarks.py b/benchmarks/run_benchmarks.py index b30fc62..8a5efed 100644 --- a/benchmarks/run_benchmarks.py +++ b/benchmarks/run_benchmarks.py @@ -16,7 +16,7 @@ "javaslicer-bench1-intra-procedural" : ("target/javaslicer-bench1-intra-procedural-1.0.0.jar", "Bench 2 ", "Bench", 8), "javaslicer-bench2-inter-procedural" : ("target/javaslicer-bench2-inter-procedural-1.0.0.jar", "Bench 2 4 ", "Bench", 8), "javaslicer-bench3-exceptions" : ("target/javaslicer-bench3-exceptions-1.0.0.jar", "Bench ", "Bench", 29), - "slicer4j-bench1-multiple-threads": ("target/slicer4j-bench1-multiple-threads-1.0.0.jar", "Bench ", "Bench", 14), + "slicer4j-bench1-multiple-threads": ("target/slicer4j-bench1-multiple-threads-1.0.0.jar", "Bench ", "Bench", 14), "slicer4j-bench2-native-framework": ("target/slicer4j-bench2-native-framework-1.0.0.jar", "Bench 0 4", "Bench", 9), "slicer4j-bench3-java-9-constructs": ("target/slicer4j-bench3-java-9-constructs-1.0.0.jar", "Bench 3 4", "Bench", 9), "slicer4j-bench4-instrumentation-classes": ("target/slicer4j-bench4-instrumentation-classes-1.0.0.jar", "Bench 22 ", "Bench", 10), @@ -25,8 +25,8 @@ defects4j_benchmarks = { "JacksonDatabind_3b": ("target/jackson-databind-2.4.1-SNAPSHOT.jar", "org.junit.runner.JUnitCore com.fasterxml.jackson.databind.deser.TestArrayDeserialization", "com.fasterxml.jackson.databind.ObjectMapper", "3062", "_readMapAndClose", "JacksonDatabind_3b/target/test-classes/:JacksonDatabind_3b/target/dependency/*"), - "Gson_4b": ("gson/target/gson-2.6-SNAPSHOT.jar", "junit.textui.TestRunner com.google.gson.stream.JsonReaderTest", "com.google.gson.stream.JsonReader", "1422", "checkLenient", "Gson_4b/gson/target/test-classes/:Gson_4b/gson/target/dependency/*"), - "JacksonCore_4b": ("target/jackson-core-2.5.0-SNAPSHOT.jar", "org.junit.runner.JUnitCore com.fasterxml.jackson.core.util.TestTextBuffer", "com.fasterxml.jackson.core.util.TextBuffer", "587", "expandCurrentSegment", "JacksonCore_4b/target/test-classes/:JacksonCore_4b/target/dependency/*"), + "Gson_4b": ("gson/target/gson-2.6-SNAPSHOT.jar", "junit.textui.TestRunner com.google.gson.stream.JsonReaderTest", "com.google.gson.stream.JsonReader", "1422", "checkLenient", "Gson_4b/gson/target/test-classes/:Gson_4b/gson/target/dependency/*"), + "JacksonCore_4b": ("target/jackson-core-2.5.0-SNAPSHOT.jar", "org.junit.runner.JUnitCore com.fasterxml.jackson.core.util.TestTextBuffer", "com.fasterxml.jackson.core.util.TextBuffer", "587", "expandCurrentSegment", "JacksonCore_4b/target/test-classes/:JacksonCore_4b/target/dependency/*"), } def count_lines_slice_slicer4j(trace): @@ -77,11 +77,14 @@ def count_lines_slice_javaslicer(trace): def build_jar(project): cwd = os.getcwd() os.chdir(f"{project}") - cmd = f"mvn clean package > /dev/null 2>&1" + print(f"Building {project}") + cmd = f"mvn clean" os.system(cmd) - cmd = f"mvn -Dmaven.test.skip=true package > /dev/null 2>&1" + cmd = f"mvn -Dmaven.test.skip=true package" os.system(cmd) - cmd = "mvn dependency:copy-dependencies > /dev/null 2>&1" + cmd = f"mvn test-compile" + os.system(cmd) + cmd = "mvn dependency:copy-dependencies" os.system(cmd) os.chdir(cwd) @@ -106,13 +109,14 @@ def run_slicer4j(project, jar_name, project_arg, extra_libs, sc_file, slice_line if os.path.isdir(out_dir): os.system(f"rm -r {out_dir}") os.mkdir(out_dir) - instr_cmd = f"java -cp \"{slicer4j_dir}/target/slicer4j-jar-with-dependencies.jar:{slicer4j_dir}/target/lib/*\" ca.ubc.ece.resess.slicer.dynamic.slicer4j.Slicer -m i -j {jar_name} -o {out_dir}/ -sl {out_dir}/static-log.log -lc {dynamic_slicing_core}/DynamicSlicingLoggingClasses/DynamicSlicingLogger.jar > /dev/null 2>&1" + instr_cmd = f"java -cp \"{slicer4j_dir}/target/slicer4j-jar-with-dependencies.jar:{slicer4j_dir}/target/lib/*\" ca.ubc.ece.resess.slicer.dynamic.slicer4j.Slicer -m i -j {jar_name} -o {out_dir}/ -sl {out_dir}/static-log.log -lc {dynamic_slicing_core}/DynamicSlicingLoggingClasses/DynamicSlicingLogger.jar" os.system(instr_cmd) instr_time = time.time() print(f"Instrumentation time (s): {instr_time-start_instr}") instrumented_jar = os.path.basename(jar_name).replace(".jar", "_i.jar") cmd = f"java -cp \"{out_dir}/{instrumented_jar}:{extra_libs}\" {project_arg} | grep \"SLICING\" > {out_dir}/trace.log" - # print(cmd) + print(f"Running instrumented jar with the following command:") + print(cmd) os.system(cmd) trace = list() with open(f"{out_dir}/trace.log", 'r') as f: @@ -137,11 +141,15 @@ def run_slicer4j(project, jar_name, project_arg, extra_libs, sc_file, slice_line line = sc.split(", ")[0] else: print(f"looking for LINENO:{slice_line}:FILE:{sc_file}") + print(f"Looking in {out_dir}/trace.log_icdg.log") with open(f"{out_dir}/trace.log_icdg.log", 'r') as f: for l in f: - if f"LINENO:{slice_line}:FILE:{sc_file}" in l: + if "goto [" in l: + pass + elif f"LINENO:{slice_line}:FILE:{sc_file}" in l: sc = l.rstrip() line = sc.split(", ")[0] + print(f"Slice criterion found: {sc}") slice_cmd = f"java -Xmx8g -cp \"{slicer4j_dir}/target/slicer4j-jar-with-dependencies.jar:{slicer4j_dir}/target/lib/*\" ca.ubc.ece.resess.slicer.dynamic.slicer4j.Slicer -j {jar_name} -m s -t {out_dir}/trace.log -o {out_dir}/ -sl {out_dir}/static-log.log -sd {slicer4j_dir}/../models/summariesManual -tw {slicer4j_dir}/../models/EasyTaintWrapperSource.txt -sp {line} -d > {out_dir}/{slice_file}_{line}.log 2>&1" os.system(slice_cmd) slice_time = time.time() diff --git a/benchmarks/slicer4j-bench1-multiple-threads/pom.xml b/benchmarks/slicer4j-bench1-multiple-threads/pom.xml index b49db40..e490cec 100644 --- a/benchmarks/slicer4j-bench1-multiple-threads/pom.xml +++ b/benchmarks/slicer4j-bench1-multiple-threads/pom.xml @@ -14,10 +14,10 @@ maven-compiler-plugin 3.8.1 - 1.6 - 1.6 + 1.7 + 1.7 true - lines,vars,source + lines,vars,source diff --git a/benchmarks/slicer4j-bench2-native-framework/pom.xml b/benchmarks/slicer4j-bench2-native-framework/pom.xml index 5f0af2b..e662512 100644 --- a/benchmarks/slicer4j-bench2-native-framework/pom.xml +++ b/benchmarks/slicer4j-bench2-native-framework/pom.xml @@ -14,10 +14,10 @@ maven-compiler-plugin 3.8.1 - 1.6 - 1.6 + 1.7 + 1.7 true - lines,vars,source + lines,vars,source diff --git a/benchmarks/slicer4j-bench4-instrumentation-classes/pom.xml b/benchmarks/slicer4j-bench4-instrumentation-classes/pom.xml index 79564a7..070a1d5 100644 --- a/benchmarks/slicer4j-bench4-instrumentation-classes/pom.xml +++ b/benchmarks/slicer4j-bench4-instrumentation-classes/pom.xml @@ -14,10 +14,10 @@ maven-compiler-plugin 3.8.1 - 1.6 - 1.6 + 1.7 + 1.7 true - lines,vars,source + lines,vars,source diff --git a/benchmarks/slicer4j-bench5-static-constructor/pom.xml b/benchmarks/slicer4j-bench5-static-constructor/pom.xml index fb70257..71c28eb 100644 --- a/benchmarks/slicer4j-bench5-static-constructor/pom.xml +++ b/benchmarks/slicer4j-bench5-static-constructor/pom.xml @@ -14,10 +14,10 @@ maven-compiler-plugin 3.8.1 - 1.6 - 1.6 + 1.7 + 1.7 true - lines,vars,source + lines,vars,source diff --git a/benchmarks/test-conditions/pom.xml b/benchmarks/test-conditions/pom.xml index d9cbac5..a098d8c 100644 --- a/benchmarks/test-conditions/pom.xml +++ b/benchmarks/test-conditions/pom.xml @@ -15,8 +15,8 @@ maven-compiler-plugin 3.8.1 - 1.6 - 1.6 + 1.7 + 1.7 diff --git a/benchmarks/test-issue1/pom.xml b/benchmarks/test-issue1/pom.xml index 8e7e0ff..c8bb67e 100644 --- a/benchmarks/test-issue1/pom.xml +++ b/benchmarks/test-issue1/pom.xml @@ -14,10 +14,10 @@ maven-compiler-plugin 3.8.1 - 1.6 - 1.6 + 1.7 + 1.7 true - lines,vars,source + lines,vars,source diff --git a/benchmarks/test-issue2/pom.xml b/benchmarks/test-issue2/pom.xml index adfed40..6dc5a15 100644 --- a/benchmarks/test-issue2/pom.xml +++ b/benchmarks/test-issue2/pom.xml @@ -14,10 +14,10 @@ maven-compiler-plugin 3.8.1 - 1.6 - 1.6 + 1.7 + 1.7 true - lines,vars,source + lines,vars,source diff --git a/benchmarks/test-issue28-1/pom.xml b/benchmarks/test-issue28-1/pom.xml new file mode 100644 index 0000000..2350755 --- /dev/null +++ b/benchmarks/test-issue28-1/pom.xml @@ -0,0 +1,26 @@ + + + + 4.0.0 + slicer4j + test-issue28-1 + 1.0.0 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.7 + 1.7 + true + lines,vars,source + + + + + + diff --git a/benchmarks/test-issue28-1/src/main/java/Main.java b/benchmarks/test-issue28-1/src/main/java/Main.java new file mode 100644 index 0000000..065aa9b --- /dev/null +++ b/benchmarks/test-issue28-1/src/main/java/Main.java @@ -0,0 +1,13 @@ +public class Main { + public static void main(String[] args) { + double[] grades = { 50.0, 60.0, 60.0, 70.0 }; + double product = 1.0; + double sum = 0.0; + for (double g1 : grades) { + sum += g1; + product *= 10.0; + } + System.out.println(sum); + System.out.println(product); + } +} diff --git a/benchmarks/test-issue28-2/pom.xml b/benchmarks/test-issue28-2/pom.xml new file mode 100644 index 0000000..065364a --- /dev/null +++ b/benchmarks/test-issue28-2/pom.xml @@ -0,0 +1,26 @@ + + + + 4.0.0 + slicer4j + test-issue28-2 + 1.0.0 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.7 + 1.7 + true + lines,vars,source + + + + + + diff --git a/benchmarks/test-issue28-2/src/main/java/Main.java b/benchmarks/test-issue28-2/src/main/java/Main.java new file mode 100644 index 0000000..e8d728a --- /dev/null +++ b/benchmarks/test-issue28-2/src/main/java/Main.java @@ -0,0 +1,14 @@ +public class Main { + public static void main(String[] args) { + int a = func(1); + int b = func(2); + int c = func(3); + test(c); + } + public static int func(int x) { + return x + 1; + } + public static void test(int x) { + System.out.println(x); + } +} diff --git a/benchmarks/test-issue5/pom.xml b/benchmarks/test-issue5/pom.xml index 5be30d8..d4391e8 100644 --- a/benchmarks/test-issue5/pom.xml +++ b/benchmarks/test-issue5/pom.xml @@ -14,10 +14,10 @@ maven-compiler-plugin 3.8.1 - 1.6 - 1.6 + 1.7 + 1.7 true - lines,vars,source + lines,vars,source diff --git a/scripts/slicer4j.py b/scripts/slicer4j.py index d9b1693..20f41a6 100644 --- a/scripts/slicer4j.py +++ b/scripts/slicer4j.py @@ -37,6 +37,7 @@ def main(): test_class = options["test_class"] test_method = options["test_method"] + test_classes_dir = options["test_classes_dir"] main_class_args = options["main_class_args"] framework_models = options["framework_models"] @@ -49,6 +50,8 @@ def main(): extra_options += "-ctrl " if options["once"]: extra_options += "-once " + if options["function_slice"]: + extra_options += "-fs " if options["data_only"] and options["ctrl_only"]: print("Conflicting arguments: data-only and control-only!") return @@ -60,7 +63,7 @@ def main(): instrumented_jar = instrument(jar_file=jar_file, out_dir=out_dir) print(f"Instrumented jar is at: {instrumented_jar}", flush=True) - run(instrumented_jar, dependencies, out_dir, test_class, test_method, main_class_args) + run(instrumented_jar, dependencies, out_dir, test_class, test_method, test_classes_dir, main_class_args) log_file, slice_graph = dynamic_slice(jar_file=jar_file, out_dir=out_dir, backward_criterion=backward_criterion, variables=options['variables'], extra_options=extra_options) @@ -68,6 +71,9 @@ def main(): print(f"Raw slice: {out_dir}/raw-slice.log") print(f"Slice graph: {slice_graph}") print(f"Slice with dependencies: {out_dir}/slice-dependencies.log") + if options["function_slice"]: + print(f"Function-level slice: {out_dir}/slice-function.log") + print(f"Pretty-print report: {out_dir}/slice-pretty.log") def instrument(jar_file: str, out_dir: str) -> str: @@ -79,10 +85,11 @@ def instrument(jar_file: str, out_dir: str) -> str: return out_dir + os.sep + instrumented_jar -def run(instrumented_jar, dependencies, out_dir, test_class, test_method, main_class_args): +def run(instrumented_jar, dependencies, out_dir, test_class, test_method, test_classes_dir, main_class_args): print("Running the instrumented JAR", flush=True) if main_class_args is None: - cmd = f"java -Xmx8g -cp \"{script_dir}/SingleJUnitTestRunner.jar:{script_dir}/junit-4.8.2.jar:{instrumented_jar}:{dependencies}/*\" SingleJUnitTestRunner {test_class}#{test_method} > {out_dir}/trace_full.log" + tcd_part = f":{test_classes_dir}" if test_classes_dir else "" + cmd = f"java -Xmx8g -cp \"{script_dir}/SingleJUnitTestRunner.jar:{script_dir}/junit-4.8.2.jar:{instrumented_jar}{tcd_part}:{dependencies}/*\" SingleJUnitTestRunner {test_class}#{test_method} > {out_dir}/trace_full.log" else: if main_class_args.startswith("\"") and main_class_args.endswith("\""): main_class_args = main_class_args[1:-1] @@ -166,12 +173,20 @@ def parse(): help="Main class to run with arguments", metavar="name", required=False) parser.add_argument("-dep", "--dependencies", dest="dependencies", help="JAR dependencies", metavar="path", required=False) + parser.add_argument("-tcd", "--test-classes-dir", dest="test_classes_dir", + help="Directory containing compiled test classes", metavar="path", required=False) + + # Function-level slicing support: expands slicing criterion from a single + # source line to all trace statements within the containing method. + parser.add_argument("-fs", "--function-slice", dest="function_slice", + help="Perform function-level slicing instead of line-level", action='store_true', required=False) args = parser.parse_args() return { "jar_file": args.jar_file, "out_dir": args.out_dir, "backward_criterion": args.backward_criterion, "variables": args.variables, "data_only": args.data_only, "ctrl_only": args.ctrl_only, "test_class": args.test_class, "test_method": args.test_method, "main_class_args": args.main_class_args, - "dependencies": args.dependencies, "framework_models": args.framework_models, "debug": args.debug, "once": args.once + "dependencies": args.dependencies, "framework_models": args.framework_models, "debug": args.debug, "once": args.once, + "test_classes_dir": args.test_classes_dir, "function_slice": args.function_slice }