- Notifications
You must be signed in to change notification settings - Fork19
Slicer4J is an accurate, low-overhead dynamic slicer for Java programs.
License
resess/Slicer4J
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
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!
If you use this tool, please cite:
Khaled Ahmed, Mieszko Lis, and Julia Rubin.Slicer4J: A Dynamic Slicer for Java. The ACM Joint European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE), 2021.<bibtex>
Also, please check out ourvideo demonstration of Slicer4J
Runs on Windows, Linux, and Mac OS
Install python3
Clone the dynamic slicing core:https://github.com/resess/DynamicSlicingCore
Requires Java Runtime Environment version 8.
Build and install the dynamic slicing core, go to the core's repo: (https://github.com/resess/DynamicSlicingCore)
cd core/mvn -Dmaven.test.skip=true clean installcd -
Build Slicer4J, go back to Slicer4J's repo
cd Slicer4J/mvn -Dmaven.test.skip=true clean installcd -
Display the command line parameters using:
java -cp "Slicer4J/target/slicer4j-jar-with-dependencies.jar:Slicer4J/target/lib/*" ca.ubc.ece.resess.slicer.dynamic.slicer4j.Slicer -h
A simpler method to use Slicer4J is by using the wrapper python script:scripts/slicer4j.py
You can list the script parameters using:python3 slicer4j.py -h
Slicer4J uses up to 8GB of RAM. The tool will crash withOutOfMemoryError
exception if the trace size is greater than 8GB.In that case, you canchange maximum heap size allocated to Slicer4J by changing the -Xmx8g to a higher value (e.g. -Xmx16g).
Parameter | Description |
---|---|
-h | show help message and exit |
-j | Path to jar file |
-o | Output folder |
-b | line to slice backward from, in the form of FileName:LineNumber |
Parameter | Description |
---|---|
-m | Main class to run with arguments, in the form of "FileName Arguments" |
-tc | Test class name to run, if this is provided, -tm must also be provided |
-tm | Test method to run |
-dep | Directory to folder containing JAR dependencies, if any |
-mod | Folder containing user-defined method models |
-d | Slice with data-flow dependencies only |
-c | Slice with control dependencies only |
-once | Get only the immediate data-flow and control dependencies of the slicing criteria |
The following is an example for defining your own method models.
For the methods in this class:
packagecom.myproject;classMyClassextendsMyOtherClass{Stringfield;publicMyClassput(Stringval){this.field =val; }publicStringget(){returnthis.field; }}
create an XML file named "com.myproject.MyClass.xml" and place it in a folder containing your method models, this is the folder we pass to Slicer4J using the-mod
parameter
For example, here's the model for the above class
<?xml version="1.0" ?><summaryfileFormatVersion="101"><hierarchysuperClass="com.myproject.MyOtherClass" /> <methods> <methodid="com.myproject.MyClass put(java.lang.String)"> <flows> <flow> <fromsourceSinkType="Parameter"ParameterIndex="0" /> <tosourceSinkType="Field"AccessPath="[com.myproject.MyClass: java.lang.String field]" AccessPathTypes="java.lang.String" /> </flow> <flow> <fromsourceSinkType="Field" /> <tosourceSinkType="Return" /> </flow> </flows> </method> <methodid="java.lang.String get()"> <flows> <flow> <fromsourceSinkType="Field"AccessPath="[java.nio.CharBuffer: char[] buffer]" AccessPathTypes="[char[]]" /> <tosourceSinkType="Return" /> </flow> </flows> </method></summary>
Theid
of each method is the method signature. Each method has flowsfrom
parameters, the receiver, and their fields,to
other parameters, the receiver, their fields, and the return.
Each flow is specified with itsourceSinkType
asParameter
,Field
, orReturn
.Parameter
is used for parameters.Field
is used for the receiver or fields of the receiver.Return
is for the method return.For parameters, we also needParameterIndex
to specify which parameter (first, second, etc.).For fields, we specify the signature of the field inAccessPath
and its type inAccessPathTypes
.
You can view the output of Slicer4J in 3 different formats:Source Map,Raw Slice, and#Graph.
Let's see the output of slicing theSliceMe
program (found underbenchmarks/SliceMe
):
1.publicclassSliceMe {2.publicstaticvoidmain(String[]args) {3.int []parsed;4.if (args.length >0){5.parsed =parse(args);6. }else {7.parsed =null;8. }9.System.out.println(parsed.length);10. }11.privatestaticint[]parse(String[]str) {12.StringfullString =String.join(", ",str);13.int []arr =newint[fullString.length()];14.for (inti =0;i<fullString.length();i++) {15.arr[i] =fullString.charAt(i)-'0';16. }17.returnarr;18. }20. }
If we run this program usingjava -cp "SliceMe-1.0.0.jar" SliceMe
(without providing any arguments to the main method), the output should be
Exceptionin thread"main" java.lang.NullPointerExceptionat SliceMe.main(SliceMe.java:9)
We can use Slicer4J to slie from theNullPointerException
at line 9.
cd scriptspython3 slicer4j.py -j ../benchmarks/SliceMe/target/SliceMe-1.0.0.jar -o sliceme_slice/ -b SliceMe:9 -m"SliceMe"
In this example, we slice from line 9 in theSliceMe.java
file:System.out.println(parsed.length);
This output is only generated if the JAR is compiled with debug information.Slicer4J outputs a list offiles-name: source-code-line-number
for each statement that compose the slice.This output is stored in the output folder in a file calledslice.log
For the example,slice.log
contains:
SliceMe:4SliceMe:7SliceMe:9
Which indicates that the slice is:
4.if (args.length >0){7.parsed =null;9.System.out.println(parsed.length);
Slicer4J outputs a list of Jimple statements with a unique Id for each statement, which we use as our intermediate format, together with the thread id of the thread they are execute in, with the source map of file and line numbers for jars that are compiled with debug information.
Every element in the list is in the formatfiles-name: source-code-line-number thread statement-id:jimple-statement
This output is stored in the output folder in a file calledraw-slice.log
For the example,raw-slice.log
contains:
SliceMe:4 1 0:$stack2 = lengthof argsSliceMe:4 1 1:if $stack2 <= 0 goto parsed = nullSliceMe:7 1 2:parsed = nullSliceMe:9 1 3:$stack4 = <java.lang.System: java.io.PrintStream out>SliceMe:9 1 4:$stack3 = lengthof parsedSliceMe:9 1 5:virtualinvoke $stack4.<java.io.PrintStream: void println(int)>($stack3)
Here we see that all statements are within the same thread (thread #1), and we see how each line is represented in Jimple (if (args.length > 0)
in the code maps to$stack2 = lengthof args
andif $stack2 <= 0 goto parsed = null
in Jimple)
Slicer4J outputs adot graph 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 calledslice-graph.pdf
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 onparsed = null
through the variableparsed
, which is written on the edge.Also,parsed = null
is control dependent onif $stack2 <= 0 goto parsed = null
.
The evaluation benchmarks are stored underbenchmarks, please check there for instructions on how to run them.
If you experience any issues, please submit an issue or contact us atkhaledea@ece.ubc.ca