-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix SVFA implementation #20
base: develop
Are you sure you want to change the base?
Changes from 36 commits
221893d
ae2b31a
42608f1
328bd75
8886ead
c8834fb
2878d85
a26b50b
b2c1bc1
0558e55
0858a27
a87af2d
b978fa0
10aa6d2
3795e47
7dd5569
8289f69
fe0f476
2b13647
56cb7a5
b1ad049
b087045
102df9b
df5a213
00a38e4
d7d2e82
f4ec53b
cf3bf95
2307d67
713419a
a435da2
77296f7
759eab6
97fc372
ec5f787
392a128
847c738
ec0fcb7
b0a15af
d82467a
c8362c3
a32a1d2
e0a67f3
583c1ca
77756a9
915798a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,4 +16,5 @@ project/plugins/project/ | |
# Scala-IDE specific | ||
.scala_dependencies | ||
.worksheet | ||
.idea | ||
.idea | ||
.gradle/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package br.unb.cic.soot.svfa.jimple | ||
|
||
trait AnalysisDepth { | ||
def maxDepth(): Int = 0 | ||
def isLimited(): Boolean= maxDepth() > 0 | ||
} | ||
|
||
trait StandardLimitedAnalysis extends AnalysisDepth { | ||
override def maxDepth(): Int = 10 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,34 +2,37 @@ package br.unb.cic.soot.svfa.jimple | |
|
||
import java.util | ||
import br.unb.cic.soot.svfa.jimple.rules.RuleAction | ||
import br.unb.cic.soot.graph.{CallSiteCloseLabel, CallSiteLabel, CallSiteOpenLabel, ContextSensitiveRegion, GraphNode, SinkNode, SourceNode, StatementNode} | ||
import br.unb.cic.soot.graph.{CallSiteCloseLabel, CallSiteLabel, CallSiteOpenLabel, ContextSensitiveRegion, GraphNode, SimpleNode, SinkNode, SourceNode, StatementNode} | ||
import br.unb.cic.soot.svfa.jimple.dsl.{DSL, LanguageParser} | ||
import br.unb.cic.soot.svfa.{SVFA, SourceSinkDef} | ||
import com.typesafe.scalalogging.LazyLogging | ||
import soot.jimple._ | ||
import soot.jimple.internal.{JArrayRef, JAssignStmt} | ||
import soot.jimple.internal.{JArrayRef, JAssignStmt, JInstanceFieldRef} | ||
import soot.jimple.spark.ondemand.DemandCSPointsTo | ||
import soot.jimple.spark.pag | ||
import soot.jimple.spark.pag.{AllocNode, PAG} | ||
import soot.jimple.spark.sets.{DoublePointsToSet, HybridPointsToSet, P2SetVisitor} | ||
import soot.toolkits.graph.ExceptionalUnitGraph | ||
import soot.toolkits.scalar.SimpleLocalDefs | ||
import soot.{ArrayType, Local, Scene, SceneTransformer, SootField, SootMethod, Transform, Value, jimple} | ||
import soot.{ArrayType, Local, PointsToSet, Scene, SceneTransformer, SootField, SootMethod, Transform, Value, jimple} | ||
|
||
import scala.collection.mutable.ListBuffer | ||
|
||
/** | ||
* A Jimple based implementation of | ||
* SVFA. | ||
*/ | ||
abstract class JSVFA extends SVFA with Analysis with FieldSensitiveness with ObjectPropagation with SourceSinkDef with LazyLogging with DSL { | ||
abstract class JSVFA extends SVFA with Analysis with AnalysisDepth with FieldSensitiveness with ObjectPropagation with SourceSinkDef with LazyLogging with DSL { | ||
|
||
val visitedMethodsDepth = new ListBuffer[SootMethod]() | ||
val visitedMethodsAllocationSites = scala.collection.mutable.Set.empty[SootMethod] | ||
var numberVisitedMethods = 0 | ||
var printDepthVisitedMethods: Boolean = false | ||
var methods = 0 | ||
val traversedMethods = scala.collection.mutable.Set.empty[SootMethod] | ||
val allocationSites = scala.collection.mutable.HashMap.empty[soot.Value, StatementNode] | ||
val arrayStores = scala.collection.mutable.HashMap.empty[Local, List[soot.Unit]] | ||
val languageParser = new LanguageParser(this) | ||
|
||
val methodRules = languageParser.evaluate(code()) | ||
|
||
/* | ||
|
@@ -55,9 +58,7 @@ abstract class JSVFA extends SVFA with Analysis with FieldSensitiveness with Obj | |
expr = invokeStmt.getInvokeExpr | ||
}catch { | ||
case e: Exception=> | ||
srcArg = invokeStmt.getInvokeExpr.getArg(from) | ||
expr = invokeStmt.getInvokeExpr | ||
println("Entrou com errro!") | ||
println("An error occurred in getInvokeExpr with args: "+invokeStmt.getInvokeExpr+" -> "+e) | ||
} | ||
if(hasBaseObject(expr) && srcArg.isInstanceOf[Local]) { | ||
val local = srcArg.asInstanceOf[Local] | ||
|
@@ -171,38 +172,62 @@ abstract class JSVFA extends SVFA with Analysis with FieldSensitiveness with Obj | |
} | ||
} | ||
|
||
|
||
def createSceneTransform(): (String, Transform) = ("wjtp", new Transform("wjtp.svfa", new Transformer())) | ||
|
||
def initAllocationSites(): Unit = { | ||
val listener = Scene.v().getReachableMethods.listener() | ||
|
||
while(listener.hasNext) { | ||
val m = listener.next().method() | ||
if (m.hasActiveBody) { | ||
val body = m.getActiveBody | ||
body.getUnits.forEach(unit => { | ||
if (unit.isInstanceOf[soot.jimple.AssignStmt]) { | ||
val right = unit.asInstanceOf[soot.jimple.AssignStmt].getRightOp | ||
if (right.isInstanceOf[NewExpr] || right.isInstanceOf[NewArrayExpr] || right.isInstanceOf[StringConstant]) { | ||
allocationSites += (right -> createNode(m, unit)) | ||
} | ||
|
||
updateAllocationSites(m) | ||
|
||
} | ||
} | ||
|
||
def updateAllocationSites(m: SootMethod): Unit = { | ||
|
||
if(visitedMethodsAllocationSites.contains(m)) { | ||
return | ||
} | ||
|
||
visitedMethodsAllocationSites.add(m) | ||
|
||
if (m.hasActiveBody) { | ||
val body = m.getActiveBody | ||
body.getUnits.forEach(unit => { | ||
if (unit.isInstanceOf[soot.jimple.AssignStmt]) { | ||
val right = unit.asInstanceOf[soot.jimple.AssignStmt].getRightOp | ||
if (right.isInstanceOf[soot.jimple.InstanceInvokeExpr]){ | ||
val method = right.asInstanceOf[soot.jimple.InstanceInvokeExpr] | ||
updateAllocationSites(method.getMethod) | ||
} | ||
else if(unit.isInstanceOf[soot.jimple.ReturnStmt]) { | ||
val exp = unit.asInstanceOf[soot.jimple.ReturnStmt].getOp | ||
if(exp.isInstanceOf[StringConstant]) { | ||
allocationSites += (exp -> createNode(m, unit)) | ||
} | ||
if (right.isInstanceOf[NewExpr] || right.isInstanceOf[NewArrayExpr] || right.isInstanceOf[StringConstant]) { | ||
allocationSites += (right -> createNode(m, unit)) | ||
} | ||
}) | ||
} | ||
} | ||
else if(unit.isInstanceOf[soot.jimple.ReturnStmt]) { | ||
val exp = unit.asInstanceOf[soot.jimple.ReturnStmt].getOp | ||
if(exp.isInstanceOf[StringConstant]) { | ||
allocationSites += (exp -> createNode(m, unit)) | ||
} | ||
} | ||
|
||
if (unit.isInstanceOf[soot.jimple.InvokeStmt]){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Se for apenas uma chamada direta de método, atualiza os allocation sites. Por exemplo: stack1.m() |
||
val method = unit.asInstanceOf[soot.jimple.InvokeStmt] | ||
updateAllocationSites(method.getInvokeExpr.getMethod) | ||
} | ||
|
||
}) | ||
} | ||
} | ||
|
||
class Transformer extends SceneTransformer { | ||
override def internalTransform(phaseName: String, options: util.Map[String, String]): Unit = { | ||
pointsToAnalysis = Scene.v().getPointsToAnalysis | ||
|
||
initAllocationSites() | ||
|
||
Scene.v().getEntryPoints.forEach(method => { | ||
traverse(method) | ||
methods = methods + 1 | ||
|
@@ -211,14 +236,22 @@ abstract class JSVFA extends SVFA with Analysis with FieldSensitiveness with Obj | |
} | ||
|
||
def traverse(method: SootMethod, forceNewTraversal: Boolean = false) : Unit = { | ||
|
||
if((!forceNewTraversal) && (method.isPhantom || traversedMethods.contains(method))) { | ||
return | ||
} | ||
|
||
if (isLimited() && visitedMethodsDepth.size >= maxDepth()){ | ||
return | ||
} | ||
|
||
if (printDepthVisitedMethods){ | ||
println(method.toString+", deep: "+ visitedMethodsDepth.size) | ||
} | ||
|
||
traversedMethods.add(method) | ||
|
||
val body = method.retrieveActiveBody() | ||
|
||
val graph = new ExceptionalUnitGraph(body) | ||
val defs = new SimpleLocalDefs(graph) | ||
|
||
|
@@ -232,8 +265,8 @@ abstract class JSVFA extends SVFA with Analysis with FieldSensitiveness with Obj | |
case _ => | ||
} | ||
}) | ||
} | ||
|
||
} | ||
|
||
def traverse(assignStmt: AssignStmt, method: SootMethod, defs: SimpleLocalDefs) : Unit = { | ||
val left = assignStmt.stmt.getLeftOp | ||
|
@@ -249,6 +282,7 @@ abstract class JSVFA extends SVFA with Analysis with FieldSensitiveness with Obj | |
case (p: JArrayRef, _) => storeArrayRule(assignStmt) | ||
case _ => | ||
} | ||
|
||
} | ||
|
||
def traverse(stmt: InvokeStmt, method: SootMethod, defs: SimpleLocalDefs) : Unit = { | ||
|
@@ -275,16 +309,26 @@ abstract class JSVFA extends SVFA with Analysis with FieldSensitiveness with Obj | |
|
||
if(analyze(callStmt.base) == SinkNode) { | ||
defsToCallOfSinkMethod(callStmt, exp, caller, defs) | ||
return // TODO: we are not exploring the body of a sink method. | ||
// For this reason, we only find one path in the | ||
// FieldSample test case, instead of two. | ||
} | ||
|
||
if(analyze(callStmt.base) == SourceNode) { | ||
if(analyze(callStmt.base) == SourceNode || analyze(callStmt.base) == SinkNode) { | ||
val source = createNode(caller, callStmt.base) | ||
svg.addNode(source) | ||
} | ||
|
||
//Add edge from defs statements to invoke statement use | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Não estava adicionando arestas para invoke statements, por exemplo:
Não adicionava aresta de stack1 (linha 1) para o statement invoke (linha 2). |
||
callStmt.base.getUseBoxes.forEach(stmt => { | ||
if(stmt.getValue.isInstanceOf[Local]) { | ||
val local = stmt.getValue.asInstanceOf[Local] | ||
|
||
defs.getDefsOfAt(local, callStmt.base).forEach(sourceStmt => { | ||
val sourceNode = createNode(caller, sourceStmt) | ||
val targetNode = createNode(caller, callStmt.base) | ||
updateGraph(sourceNode, targetNode) | ||
}) | ||
} | ||
}) | ||
|
||
for(r <- methodRules) { | ||
if(r.check(callee)) { | ||
r.apply(caller, callStmt.base.asInstanceOf[jimple.Stmt], defs) | ||
|
@@ -314,8 +358,14 @@ abstract class JSVFA extends SVFA with Analysis with FieldSensitiveness with Obj | |
stringToCallSite(caller, callee, callStmt.base, s) | ||
} | ||
}) | ||
visitedMethodsDepth += callee.retrieveActiveBody().getMethod | ||
|
||
numberVisitedMethods += 1 | ||
|
||
traverse(callee) | ||
|
||
visitedMethodsDepth -= callee.retrieveActiveBody().getMethod | ||
|
||
} | ||
|
||
private def applyPhantomMethodCallRule(callStmt: Statement, exp: InvokeExpr, caller: SootMethod, defs: SimpleLocalDefs) = { | ||
|
@@ -456,6 +506,7 @@ abstract class JSVFA extends SVFA with Analysis with FieldSensitiveness with Obj | |
}) | ||
} | ||
else { | ||
|
||
// val allocationNodes = findAllocationSites(base) | ||
|
||
// val allocationNodes = findAllocationSites(base, true, fieldRef.getField) | ||
|
@@ -468,8 +519,10 @@ abstract class JSVFA extends SVFA with Analysis with FieldSensitiveness with Obj | |
}) | ||
// }) | ||
// } | ||
|
||
} | ||
} | ||
|
||
} | ||
|
||
def storeArrayRule(assignStmt: AssignStmt) { | ||
|
@@ -487,7 +540,6 @@ abstract class JSVFA extends SVFA with Analysis with FieldSensitiveness with Obj | |
val csCloseLabel = createCSCloseLabel(caller, callStmt, callee) | ||
svg.addEdge(source, target, csCloseLabel) | ||
|
||
|
||
if(local.getType.isInstanceOf[ArrayType]) { | ||
val stores = arrayStores.getOrElseUpdate(local, List()) | ||
stores.foreach(sourceStmt => { | ||
|
@@ -741,4 +793,12 @@ abstract class JSVFA extends SVFA with Analysis with FieldSensitiveness with Obj | |
} | ||
} | ||
|
||
def setPrintDepthVisitedMethods(printDepthVisitedMethods: Boolean) { | ||
this.printDepthVisitedMethods = printDepthVisitedMethods | ||
} | ||
|
||
def getNumberVisitedMethods(): Int = { | ||
return numberVisitedMethods | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package samples; | ||
|
||
public class AllocationFlowTest1 { | ||
private Point p; | ||
|
||
public void main() { | ||
Integer x = new Integer(3); //Left | ||
x = null; | ||
Integer y; | ||
y = x; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package samples; | ||
|
||
public class AllocationFlowTest2 { | ||
private Point p; | ||
|
||
public void main() { | ||
Integer x = new Integer(3); //Left | ||
Integer y; | ||
y = x; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package samples; | ||
|
||
public class Field1 { | ||
// Integer p = new Integer(1); | ||
public void main() { | ||
Integer x, p; | ||
p = new Integer(3); //Left | ||
x = new Integer(p); //Right | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package samples; | ||
|
||
public class Field2 { | ||
private Point p; | ||
|
||
public void main() { | ||
p.y = 3; //Left | ||
p.y = p.x + 5; //Right | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package samples; | ||
|
||
public class Field3 { | ||
private Point p; | ||
|
||
public void main() { | ||
p.y = 3; //Left | ||
p.y = 5; //Right | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Se na direita também tiver uma chamada de método, atualiza os allocation sites. Por exemplo: stack0 = stack1.m()