-
Notifications
You must be signed in to change notification settings - Fork 178
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
A NullPointerAnalysis example, not completed yet
- Loading branch information
1 parent
198d521
commit 24f0196
Showing
10 changed files
with
317 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} | ||
|
||
} | ||
|
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
67 changes: 67 additions & 0 deletions
67
src/main/java/dev/navids/soottutorial/intraanalysis/npanalysis/NPAMain.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
src/main/java/dev/navids/soottutorial/intraanalysis/npanalysis/NullFlowSet.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()); | ||
} | ||
} |
109 changes: 109 additions & 0 deletions
109
src/main/java/dev/navids/soottutorial/intraanalysis/npanalysis/NullPointerAnalysis.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
}); | ||
} | ||
|
||
} | ||
|
2 changes: 1 addition & 1 deletion
2
...ottutorial/intraanalysis/UsageFinder.java → ...ntraanalysis/usagefinder/UsageFinder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters