Skip to content

Commit

Permalink
A NullPointerAnalysis example, not completed yet
Browse files Browse the repository at this point in the history
  • Loading branch information
noidsirius committed Sep 18, 2019
1 parent 198d521 commit 24f0196
Show file tree
Hide file tree
Showing 10 changed files with 317 additions and 9 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,17 @@ In this chapter, you will visit a very simple code example to be familiar with S

|Title |Tutorial | Soot Code | Example Input |
| :---: |:-------------: |:-------------:| :-----:|
|Find usages of a method| | [UsageFinder.java](https://github.com/noidsirius/SootTutorial/tree/master/src/main/java/dev/navids/soottutorial/intraanalysis/UsageFinder.java) | [UsageExample.java](https://github.com/noidsirius/SootTutorial/tree/master/demo/IntraAnalysis/UsageExample.java) |
|Find usages of a method| | [UsageFinder.java](https://github.com/noidsirius/SootTutorial/tree/master/src/main/java/dev/navids/soottutorial/intraanalysis/usagefinder/UsageFinder.java) | [UsageExample.java](https://github.com/noidsirius/SootTutorial/tree/master/demo/IntraAnalysis/usagefinder/UsageExample.java) |
|Null Pointer Analysis ||[NullPointerAnalysis](https://github.com/noidsirius/SootTutorial/tree/master/src/main/java/dev/navids/soottutorial/intraanalysis/npanalysis/) | [NullPointerExample.java](https://github.com/noidsirius/SootTutorial/tree/master/demo/IntraAnalysis/NullPointerExample.java) |


### 3: Manipulate the code (:construction: WIP)
### 4: Call Graphs (:construction: WIP)
### 5: Interprocedural analysis (:construction: WIP)
|Title |Tutorial | Soot Code | Example Input |
| :---: |:-------------: |:-------------:| :-----:|
| | | | |

### 6: Android (:construction: WIP)

|Title |Tutorial | Soot Code | Example Input |
Expand Down
64 changes: 64 additions & 0 deletions demo/IntraAnalysis/NullPointerExample.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
public class NullPointerExample {

public void methodA(){
Data d = new Data("Something");
use(d);
d = null;
use(d);
}

public void methodB(Data param){
use(param);
}


public void methodC(){
Data mayNullData = null;
Data notNull = null;
Data mustNull = new Data("Must Be null");
use(mayNullData);
use(notNull);
use(mustNull);
Object o = new Object();
if(o.hashCode() % 2 == 0) {
mayNullData = new Data("I'm not null anymore");
notNull = new Data("Me neither");
mustNull = null;
}
else {
notNull = new Data("Not even in this branch");
mustNull = null;
}
use(mayNullData);
use(notNull);
use(mustNull);
}

public void methodD(){
Data nullData = getNullString();
use(nullData);
Data helloWorldData = getHelloWorld();
use(helloWorldData);
}

public void use(Data d){
System.out.println(d.message);
}

public Data getNullString(){
return null;
}

public Data getHelloWorld(){
return new Data("HelloWorld");
}

class Data {
String message;
public Data(String message){
this.message = message;
}
}

}

5 changes: 0 additions & 5 deletions demo/IntraAnalysis/Printer.java

This file was deleted.

6 changes: 6 additions & 0 deletions demo/IntraAnalysis/UsageExample.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,11 @@ public void methodB(int n){
Printer p = new Printer();
p.println(s);
}

class Printer {
public void println(String line){
// do nothing
}
}
}

2 changes: 1 addition & 1 deletion demo/compile.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ for DIR in `ls -d */`; do
echo "Compiling directory $DIR"
cd $DIR
rm $(find . -name "*.class") 2> /dev/null
javac $(find . -name "*.java")
javac -g $(find . -name "*.java")
cd ../
done
5 changes: 4 additions & 1 deletion src/main/java/dev/navids/soottutorial/Main.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package dev.navids.soottutorial;

import dev.navids.soottutorial.hellosoot.HelloSoot;
import dev.navids.soottutorial.intraanalysis.UsageFinder;
import dev.navids.soottutorial.intraanalysis.npanalysis.NPAMain;
import dev.navids.soottutorial.intraanalysis.usagefinder.UsageFinder;

import java.util.Arrays;

Expand All @@ -16,6 +17,8 @@ public static void main(String[] args){
HelloSoot.main(restOfTheArgs);
else if(args[0].equals("UsageFinder"))
UsageFinder.main(restOfTheArgs);
else if(args[0].equals("NullPointerAnalysis"))
NPAMain.main(restOfTheArgs);
else
System.err.println("The class '" + args[0] + "' does not exists or does not have a main method.");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package dev.navids.soottutorial.intraanalysis.npanalysis;

import soot.*;
import soot.jimple.InvokeStmt;
import soot.jimple.JimpleBody;
import soot.options.Options;
import soot.toolkits.graph.TrapUnitGraph;
import soot.toolkits.graph.UnitGraph;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class NPAMain {
public static String sourceDirectory = System.getProperty("user.dir") + File.separator + "demo" + File.separator + "IntraAnalysis";
public static String clsName = "NullPointerExample";

public static void setupSoot() {
G.reset();
Options.v().set_soot_classpath(sourceDirectory);
Options.v().set_prepend_classpath(true);
Options.v().set_keep_line_number(true);
Options.v().set_keep_offset(true);
SootClass sc = Scene.v().loadClassAndSupport(clsName);
sc.setApplicationClass();
Scene.v().loadNecessaryClasses();
}


public static void main(String[] args) {
setupSoot();
SootClass mainClass = Scene.v().getSootClass(clsName);
for (SootMethod sm : mainClass.getMethods()) {
System.out.println("Method: " + sm.getSignature());
JimpleBody body = (JimpleBody) sm.retrieveActiveBody();
UnitGraph unitGraph = new TrapUnitGraph(body);
List<NullPointerAnalysis> npAnalyzers = new ArrayList<>();
npAnalyzers.add(new NullPointerAnalysis(unitGraph, NullPointerAnalysis.AnalysisMode.MUST));
npAnalyzers.add(new NullPointerAnalysis(unitGraph, NullPointerAnalysis.AnalysisMode.MAY_O));
npAnalyzers.add(new NullPointerAnalysis(unitGraph, NullPointerAnalysis.AnalysisMode.MAY_P));
int c = 0;
for(Unit unit : body.getUnits()){
c++;
// System.out.println("("+c+") " + unit + " --- " + mayNPAnalysis.getFlowBefore(unit) + " " + mustNPAnalysis.getFlowBefore(unit));
// if(nullPointerAnalysis.getFlowBefore(unit).size() == 0)
// continue;
for(ValueBox usedValueBox : unit.getUseBoxes()){
if(usedValueBox.getValue() instanceof Local){
Local usedLocal = (Local) usedValueBox.getValue();
for(NullPointerAnalysis npa: npAnalyzers){
if(npa.getFlowBefore(unit).contains(usedLocal)){
System.out.println(" Line " + unit.getJavaSourceStartLineNumber() +": " + npa.analysisMode + " NullPointer usage of local " + usedLocal + " in unit " + unit);
}
}

// if(mustNPAnalysis.getFlowBefore(unit).contains(usedLocal)){
// System.out.println(" Line " + unit.getJavaSourceStartLineNumber() +": MUST NullPointer usage of local " + usedLocal + " in unit (" + c +") " + unit);
// }
}
if(unit instanceof InvokeStmt && usedValueBox.getValue().getType().equals(NullType.v())){
System.out.println(" Line " + unit.getJavaSourceStartLineNumber() +": MUST NullPointer usage in unit (" + c +") " + unit);
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package dev.navids.soottutorial.intraanalysis.npanalysis;

import soot.Local;
import soot.toolkits.scalar.AbstractBoundedFlowSet;

import java.util.*;
import java.util.stream.Collectors;

public class NullFlowSet extends AbstractBoundedFlowSet<Local> {

private Set<Local> nullLocals = new HashSet<>();
public NullFlowSet() {
super();
}

@Override
public NullFlowSet clone() {
NullFlowSet myClone = new NullFlowSet();
myClone.nullLocals.addAll(this.nullLocals);
return myClone;
}

@Override
public boolean isEmpty() {
return nullLocals.isEmpty();
}

@Override
public int size() {
return nullLocals.size();
}

@Override
public void add(Local local) {
nullLocals.add(local);
}

@Override
public void remove(Local local) {
if(nullLocals.contains(local))
nullLocals.remove(local);
}

@Override
public boolean contains(Local local) {
return nullLocals.contains(local);
}

@Override
public Iterator<Local> iterator() {
return nullLocals.iterator();
}

@Override
public List<Local> toList() {
return nullLocals.stream().collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package dev.navids.soottutorial.intraanalysis.npanalysis;


import soot.Local;
import soot.Unit;
import soot.jimple.*;
import soot.toolkits.graph.DirectedGraph;
import soot.toolkits.scalar.ForwardFlowAnalysis;

public class NullPointerAnalysis extends ForwardFlowAnalysis<Unit, NullFlowSet> {

enum AnalysisMode {
MUST,
MAY_P,
MAY_O
}
AnalysisMode analysisMode;
public NullPointerAnalysis(DirectedGraph graph, AnalysisMode analysisMode) {
super(graph);
this.analysisMode = analysisMode;
doAnalysis();
}

@Override
protected void flowThrough(NullFlowSet inSet, Unit unit, NullFlowSet outSet) {
inSet.copy(outSet);
kill(inSet, unit, outSet);
generate(inSet, unit, outSet);
}

@Override
protected NullFlowSet newInitialFlow() {
return new NullFlowSet();
}


@Override
protected void merge(NullFlowSet inSet1, NullFlowSet inSet2, NullFlowSet outSet) {
if(analysisMode != AnalysisMode.MUST)
inSet1.union(inSet2, outSet);
else
inSet1.intersection(inSet2, outSet);
}

@Override
protected void copy(NullFlowSet source, NullFlowSet dest) {
source.copy(dest);
}

protected void kill(NullFlowSet inSet, Unit unit, NullFlowSet outSet){
unit.apply(new AbstractStmtSwitch() {
@Override
public void caseAssignStmt(AssignStmt stmt) {
Local leftOp = (Local) stmt.getLeftOp();
outSet.remove(leftOp);
}
});
}

protected void generate(NullFlowSet inSet, Unit unit, NullFlowSet outSet){
unit.apply(new AbstractStmtSwitch() {
@Override
public void caseAssignStmt(AssignStmt stmt) {
Local leftOp = (Local) stmt.getLeftOp();
stmt.getRightOp().apply(new AbstractJimpleValueSwitch() {
@Override
public void caseLocal(Local v) {
if (inSet.contains(v))
outSet.add(leftOp);
}

@Override
public void caseNullConstant(NullConstant v) {
outSet.add(leftOp);
}

@Override
public void caseInterfaceInvokeExpr(InterfaceInvokeExpr v) {
if(analysisMode == AnalysisMode.MAY_P)
outSet.add(leftOp);
}

@Override
public void caseStaticInvokeExpr(StaticInvokeExpr v) {
if(analysisMode == AnalysisMode.MAY_P)
outSet.add(leftOp);
}

@Override
public void caseVirtualInvokeExpr(VirtualInvokeExpr v) {
if(analysisMode == AnalysisMode.MAY_P)
outSet.add(leftOp);
}
});
}

@Override
public void caseIdentityStmt(IdentityStmt stmt) {

Local leftOp = (Local) stmt.getLeftOp();
if(analysisMode == AnalysisMode.MAY_P)
if(!(stmt.getRightOp() instanceof ThisRef))
outSet.add(leftOp);
}
});
}

}

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.navids.soottutorial.intraanalysis;
package dev.navids.soottutorial.intraanalysis.usagefinder;

import soot.*;
import soot.jimple.AbstractStmtSwitch;
Expand Down

0 comments on commit 24f0196

Please sign in to comment.