Skip to content

Commit

Permalink
Merge branch 'develop' into optimize/asmmethodsource_loop_unroll_remo…
Browse files Browse the repository at this point in the history
…ve_necessity_to_reverse

# Conflicts:
#	sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java
  • Loading branch information
swissiety committed Oct 26, 2023
2 parents 801bc94 + baa460f commit 4c43c27
Show file tree
Hide file tree
Showing 275 changed files with 2,736 additions and 1,484 deletions.
9 changes: 9 additions & 0 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
cff-version: 1.2.0
title: SootUp
message: 'If you use SootUp, please cite it as below.'
type: software
authors:
- given-names: Soot-oss
repository-code: 'https://github.com/soot-oss/SootUp'
version: 1.1.2
date-released: '2023-06-12'
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<img width="350px" src="https://github.com/soot-oss/SootUp/blob/develop/docs/SootUpLogo.svg">
</p>

# SootUp library ![Java CI with Maven](https://github.com/soot-oss/SootUp/workflows/Java%20CI%20with%20Maven/badge.svg?branch=develop) [![codecov](https://codecov.io/gh/soot-oss/SootUp/branch/develop/graph/badge.svg?token=ELA7U7IAWD)](https://codecov.io/gh/soot-oss/SootUp)
# SootUp library ![Java CI with Maven](https://github.com/soot-oss/SootUp/workflows/Java%20CI%20with%20Maven/badge.svg?branch=develop) [![codecov](https://codecov.io/gh/soot-oss/SootUp/branch/develop/graph/badge.svg?token=ELA7U7IAWD)](https://codecov.io/gh/soot-oss/SootUp) [![javadoc](https://javadoc.io/badge2/org.soot-oss/sootup.core/javadoc.svg)](https://javadoc.io/doc/org.soot-oss/sootup.core)

This is the home of the **SootUp** project.
A complete overhaul of the good, old static analysis framework [Soot](https://github.com/soot-oss/soot).
Expand All @@ -25,7 +25,7 @@ Do you have questions? Feel free to start a [Discussion](https://github.com/soot
#### (compared to its predecessor [Soot](https://github.com/soot-oss/soot).)
- [x] New Improved API (without Globals/Singletons)
- [x] Fully-Parallelizable Architecture
- [x] Enables lazyloading of classes (no interleaved loading of used/dependend classes anymore)
- [x] Enables lazyloading of classes (no interleaved loading of used/dependent classes anymore)
- [x] Fail early strategy - input validation while constructing/building objects
- [x] Up-to-Date (i.e. Java8!) Sourcecode Frontend
- [x] Full Java 21 Support for Bytecode
Expand All @@ -40,7 +40,7 @@ See our [Todo list](https://github.com/soot-oss/SootUp/wiki/TODOs).
## Feel free to improve Soot!

### Feedback and Feature Requests
For feedbacks and feature requests, best create appropriate [issues](../../issues).
For feedback and feature requests, best create appropriate [issues](../../issues).

### Collaboration
You want to collaborate? Please read our [coding guidelines and the contributors notice](../../wiki/contribution-to-SootUp).
Expand Down
28 changes: 15 additions & 13 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,8 @@ You can use bytecode analysis typically when you do not have access to the sourc
!!! example "Create a project to analyze Java bytecode"

~~~java
Path pathToBinary = Paths.get("src/test/resources/BasicSetup/binary");

AnalysisInputLocation<JavaSootClass> inputLocation =
PathBasedAnalysisInputLocation.createForClassContainer(pathToBinary);
new JavaClassPathAnalysisInputLocation("path2Binary");
JavaLanguage language = new JavaLanguage(8);

Expand All @@ -53,13 +51,15 @@ You can use bytecode analysis typically when you do not have access to the sourc

If you have access to the source code, it is also possible to create a project for analyzing source code. Following example shows how to create project for analyzing Java source code.

!!! info "Experimental"

The source code frontend is experimental and should only be used for testing purposes. You should compile the code for analysis first and use the bytecode frontend instead.

!!! example "Create a project to analyze Java source code"

~~~java
Path pathToSource = Paths.get("src/test/resources/BasicSetup/source");

AnalysisInputLocation<JavaSootClass> inputLocation =
new JavaSourcePathAnalysisInputLocation(pathToSource.toString());
new JavaSourcePathAnalysisInputLocation("path2Source");
JavaLanguage language = new JavaLanguage(8);

Expand All @@ -72,7 +72,7 @@ If you have a [Jimple](../jimple) file, you can create a project for analyzing j
!!! example "Create a project to analyze jimple code"

~~~java
Path pathToJimple = Paths.get("src/test/resources/BasicSetup/jimple");
Path pathToJimple = Paths.get("path2Jimple");

AnalysisInputLocation<JavaSootClass> inputLocation =
new JimpleAnalysisInputLocation(pathToJimple);
Expand Down Expand Up @@ -120,10 +120,13 @@ Let's say the following is the target program that we want to analyze:

}

public static void main(String[] var0) {

System.out.println("Hello World!");

public static void main(String[] args) {
HelloWorld hw = new HelloWorld();
hw.hello();
}

public void hello() {

}
}
Expand Down Expand Up @@ -209,9 +212,8 @@ Below we show a comparison of the code so far with the same functionality in soo
=== "SootUp"

``` java
Path pathToBinary = Paths.get("src/test/resources/BasicSetup/binary");
AnalysisInputLocation<JavaSootClass> inputLocation =
PathBasedAnalysisInputLocation.createForClassContainer(pathToBinary);
new JavaClassPathAnalysisInputLocation("path2Binary");

JavaLanguage language = new JavaLanguage(8);

Expand Down
Binary file added shared-test-resources/bugfixes/Indy.class
Binary file not shown.
17 changes: 17 additions & 0 deletions shared-test-resources/bugfixes/Indy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import java.time.LocalDate;
import java.time.Period;
import java.util.stream.Stream;
import java.util.stream.IntStream;

/** conversion failed when there is a merge (here: after the if) and an invokedynamic followed */
class Indy{
public IntStream test(IntStream s) {
int sign;
if (s.isParallel()) {
sign = 1;
}else{
sign = -1;
}
return s.map(n -> n+42);
}
}
Binary file modified shared-test-resources/java-miniapps/MiniApp.jar
Binary file not shown.
1 change: 1 addition & 0 deletions shared-test-resources/java-miniapps/src/NoClass.class
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is not a class
1 change: 1 addition & 0 deletions shared-test-resources/java-miniapps/src/junkclass
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
this is a test file to check if it recognized as class
Binary file modified shared-test-resources/jigsaw-examples/requires_exports/jar/modb.jar
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
this is a test file to check if it recognized as class
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
record RecordTest(int a, String b) {
public RecordTest(int a, String b) {
this.a = a;
this.b = b;
}
}
1 change: 1 addition & 0 deletions shared-test-resources/wala-tests/FakeJava.java
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is a fake java file
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package sootup.analysis.interprocedural.icfg;

import java.util.*;
import java.util.stream.Collectors;
import sootup.core.graph.BasicBlock;
import sootup.core.graph.StmtGraph;
import sootup.core.jimple.common.expr.JNewExpr;
import sootup.core.jimple.common.stmt.JAssignStmt;
import sootup.core.jimple.common.stmt.Stmt;
import sootup.core.model.SootClass;
import sootup.core.model.SootMethod;
import sootup.core.signatures.MethodSignature;
import sootup.core.signatures.MethodSubSignature;
import sootup.core.typehierarchy.MethodDispatchResolver;
import sootup.core.types.VoidType;
import sootup.core.util.DotExporter;
import sootup.core.views.View;

public class ICFGDotExporter {

public static String buildICFGGraph(
Map<MethodSignature, StmtGraph> signatureToStmtGraph, View<? extends SootClass<?>> view) {
final StringBuilder sb = new StringBuilder();
DotExporter.buildDiGraphObject(sb);
Map<Integer, MethodSignature> calls;
calls = computeCalls(signatureToStmtGraph, view);
for (Map.Entry<MethodSignature, StmtGraph> entry : signatureToStmtGraph.entrySet()) {
String graph = DotExporter.buildGraph(entry.getValue(), true, calls, entry.getKey());
sb.append(graph + "\n");
}
sb.append("}");
return sb.toString();
}

/**
* This method finds out all the calls made in the given StmtGraphs, so it can be edged to other
* methods.
*/
public static Map<Integer, MethodSignature> computeCalls(
Map<MethodSignature, StmtGraph> stmtGraphSet, View<? extends SootClass<?>> view) {
Map<Integer, MethodSignature> calls = new HashMap<>();
for (StmtGraph stmtGraph : stmtGraphSet.values()) {
Collection<? extends BasicBlock<?>> blocks;
try {
blocks = stmtGraph.getBlocksSorted();
} catch (Exception e) {
blocks = stmtGraph.getBlocks();
}
for (BasicBlock<?> block : blocks) {
List<Stmt> stmts = block.getStmts();
for (Stmt stmt : stmts) {
if (stmt.containsInvokeExpr()) {
MethodSignature methodSignature = stmt.getInvokeExpr().getMethodSignature();
int hashCode = stmt.hashCode();
calls.put(hashCode, methodSignature);
// compute all the classes that are made to the subclasses as well
connectEdgesToSubClasses(methodSignature, view, calls);
} else if (stmt instanceof JAssignStmt) {
JAssignStmt jAssignStmt = (JAssignStmt) stmt;
Integer currentHashCode = stmt.hashCode();
if (jAssignStmt.getRightOp() instanceof JNewExpr) {
// if the statement is a new expression, then there will be calls to its static
// initializers (init and clinit), so need to compute calls to them as well
for (MethodSignature methodSignature : stmtGraphSet.keySet()) {
SootMethod clintMethod =
view.getMethod(methodSignature.getDeclClassType().getStaticInitializer())
.orElse(null);
if (clintMethod != null) {
if (!calls.containsKey(stmt.hashCode())) {
calls.put(stmt.hashCode(), methodSignature);
} else {
MethodSignature secondInitMethodSignature = calls.get(currentHashCode);
currentHashCode =
stmtGraphSet.get(secondInitMethodSignature).getStartingStmt().hashCode();
calls.put(currentHashCode, methodSignature);
}
}
}
}
}
}
}
}
return calls;
}

public static Set<MethodSignature> getMethodSignatureInSubClass(
MethodSignature targetMethodSignature, View<? extends SootClass<?>> view) {
try {
return MethodDispatchResolver.resolveAllDispatches(view, targetMethodSignature).stream()
.map(
methodSignature ->
MethodDispatchResolver.resolveConcreteDispatch(view, methodSignature))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toSet());
} catch (Exception e) {
return null;
}
}

public static void connectEdgesToSubClasses(
MethodSignature methodSignature,
View<? extends SootClass<?>> view,
Map<Integer, MethodSignature> calls) {
Set<MethodSignature> methodSignatureInSubClass =
getMethodSignatureInSubClass(methodSignature, view);
if (methodSignatureInSubClass != null) {
methodSignatureInSubClass.forEach(
subclassmethodSignature -> {
Optional<? extends SootMethod> method = view.getMethod(methodSignature);
MethodSignature initMethod =
new MethodSignature(
subclassmethodSignature.getDeclClassType(),
new MethodSubSignature(
"<init>", Collections.emptyList(), VoidType.getInstance()));
if (method.isPresent()
&& !subclassmethodSignature.toString().equals(initMethod.toString())) {
if (method.get().hasBody()) {
calls.put(
method.get().getBody().getStmtGraph().getStartingStmt().hashCode(),
subclassmethodSignature);
}
}
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import sootup.callgraph.CallGraph;
import sootup.callgraph.CallGraphAlgorithm;
import sootup.callgraph.ClassHierarchyAnalysisAlgorithm;
import sootup.core.graph.StmtGraph;
import sootup.core.jimple.common.stmt.Stmt;
import sootup.core.model.SootClass;
import sootup.core.model.SootMethod;
Expand Down Expand Up @@ -148,6 +149,33 @@ public JimpleBasedInterproceduralCFG(
initializeStmtToOwner();
}

public String buildICFGGraph(CallGraph callGraph) {
Map<MethodSignature, StmtGraph> signatureToStmtGraph = new LinkedHashMap<>();
computeAllCalls(mainMethodSignature, signatureToStmtGraph, callGraph);
return ICFGDotExporter.buildICFGGraph(signatureToStmtGraph, view);
}

public void computeAllCalls(
MethodSignature methodSignature,
Map<MethodSignature, StmtGraph> signatureToStmtGraph,
CallGraph callGraph) {
final Optional<? extends SootMethod> methodOpt = view.getMethod(methodSignature);
// return if the methodSignature is already added to the hashMap to avoid stackoverflow error.
if (signatureToStmtGraph.containsKey(methodSignature)) return;
if (methodOpt.isPresent()) {
SootMethod sootMethod = methodOpt.get();
if (sootMethod.hasBody()) {
StmtGraph<?> stmtGraph = sootMethod.getBody().getStmtGraph();
signatureToStmtGraph.put(methodSignature, stmtGraph);
}
}
callGraph
.callsFrom(methodSignature)
.forEach(
nextMethodSignature ->
computeAllCalls(nextMethodSignature, signatureToStmtGraph, callGraph));
}

private CallGraph initCallGraph() {
CallGraphAlgorithm cga = new ClassHierarchyAnalysisAlgorithm(view);
return cga.initialize(Collections.singletonList(mainMethodSignature));
Expand Down
Loading

0 comments on commit 4c43c27

Please sign in to comment.