Skip to content
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

Open
wants to merge 46 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
221893d
fix: add value line in to string
Nov 3, 2022
ae2b31a
Merge branch 'rbonifacio:develop' into develop
galilasmb Mar 1, 2023
42608f1
fix: add config to ignore resolution errors from soot
May 24, 2023
328bd75
Merge branch 'rbonifacio:develop' into develop
galilasmb May 24, 2023
8886ead
feat: print depth methods visited and number of methods
May 31, 2023
c8834fb
fix: add edge to fields
Jun 7, 2023
2878d85
fix: adjusting algorithm
Jun 8, 2023
a26b50b
fix: adjusting field algoritms
Jun 12, 2023
b2c1bc1
fix: adjusting to casting
Jun 12, 2023
0558e55
fix: adjusting build.sbt
Jun 12, 2023
0858a27
refactoring: removing entryPointMethod
Jun 12, 2023
a87af2d
fix: adjusting algorithm
Jun 13, 2023
b978fa0
fix: adjusting pattern match
Jun 13, 2023
10aa6d2
fix: adjuting report number of conflicts
Jun 13, 2023
3795e47
refact: removing unused variables
Jun 13, 2023
7dd5569
refact: add field number line
Jun 15, 2023
8289f69
tests: adjusting tests
Jun 15, 2023
fe0f476
fix: add fields in allocationSites
Jun 15, 2023
2b13647
fix: adjusting load and store algorithm
Jun 16, 2023
56cb7a5
fix: adjusting algoritm
Jun 22, 2023
b1ad049
tests: new tests
Jun 22, 2023
b087045
fix: removing used code
Jun 22, 2023
102df9b
fix: removing used code
Jun 22, 2023
df5a213
fix: removing used code
Jun 22, 2023
00a38e4
tests: add more tests
Jun 22, 2023
d7d2e82
feat: add flag enableAllocationSiteDF
Jun 23, 2023
f4ec53b
fix: create assignStatements field
Jun 26, 2023
cf3bf95
refact: renaming variable
Jun 26, 2023
2307d67
refact: removing unsed methods
Jun 26, 2023
713419a
error: adjusting
Jun 26, 2023
a435da2
fix: adjusting tests and fixing algoritm
Jun 27, 2023
77296f7
tests: add more tests with integer
Jun 27, 2023
759eab6
fix: adjusting depth limit to 10
Jul 5, 2023
97fc372
fix: adjusting and refactoring
Jul 10, 2023
ec5f787
refact: renaming variable
Jul 10, 2023
392a128
feat: add call to InstanceInvokeExpr with an AssignStmt
Jul 11, 2023
847c738
fix: adjusting total visited methods
Jul 13, 2023
ec0fcb7
fix: updating allocation site before
Jul 13, 2023
b0a15af
adding visited methods in the node graph
Aug 15, 2023
d82467a
udpating svfa
Sep 22, 2023
c8362c3
adjusting path visited method
Sep 22, 2023
a32a1d2
add use field algorithm
Nov 13, 2023
e0a67f3
fix: adjusting patern matching
Nov 29, 2023
583c1ca
feat: add support for java 9 or higher
barbosamaatheus May 30, 2024
77756a9
feat: add support for java 9 or higher
barbosamaatheus May 30, 2024
915798a
Merge pull request #1 from barbosamaatheus/testing_fields_svfa
galilasmb May 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ project/plugins/project/
# Scala-IDE specific
.scala_dependencies
.worksheet
.idea
.idea
.gradle/
12 changes: 6 additions & 6 deletions src/main/scala/br/unb/cic/soot/graph/Graph.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ trait GraphNode {
def unit(): soot.Unit
def method(): soot.SootMethod
def show(): String
def line(): Int
}

trait LambdaNode extends scala.AnyRef {
Expand All @@ -51,17 +52,14 @@ case class Statement(className: String, method: String, stmt: String, line: Int,
case class StatementNode(value: Statement, nodeType: NodeType) extends GraphNode {
type T = Statement

// override def show(): String = "(" ++ value.method + ": " + value.stmt + " - " + value.line + " <" + nodeType.toString + ">)"
override def show(): String = value.stmt
override def show(): String = "(" ++ value.method + ": " + value.stmt + " - " + value.line + " <" + nodeType.toString + ">)"

override def toString: String =
"Node(" + value.method + "," + value.stmt + "," + "," + nodeType.toString + ")"
"Node(" + value.method + "," + value.stmt + "," + value.line+ "," + nodeType.toString + ")"

override def equals(o: Any): Boolean = {
o match {
// case stmt: StatementNode => stmt.value.toString == value.toString
// case stmt: StatementNode => stmt.value == value && stmt.nodeType == nodeType
case stmt: StatementNode => stmt.value.className.equals(value.className) &&
case stmt: StatementNode => stmt.value.className.equals(value.className) &&
stmt.value.method.equals(value.method) &&
stmt.value.stmt.equals(value.stmt) &&
stmt.value.line.equals(value.line) &&
Expand All @@ -75,6 +73,8 @@ case class StatementNode(value: Statement, nodeType: NodeType) extends GraphNode
override def unit(): soot.Unit = value.sootUnit

override def method(): SootMethod = value.sootMethod

override def line(): Int = value.line
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ abstract class SootConfiguration {
Options.v().set_keep_line_number(true)
Options.v().set_prepend_classpath(true)
Options.v().setPhaseOption("jb", "use-original-names:true")
Options.v().set_ignore_resolution_errors(true);
configureCallGraphPhase()

Scene.v().loadNecessaryClasses()
Expand Down
10 changes: 10 additions & 0 deletions src/main/scala/br/unb/cic/soot/svfa/jimple/AnalysisDepth.scala
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
}
122 changes: 91 additions & 31 deletions src/main/scala/br/unb/cic/soot/svfa/jimple/JSVFA.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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())

/*
Expand All @@ -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]
Expand Down Expand Up @@ -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)
Copy link
Author

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()

}
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]){
Copy link
Author

Choose a reason for hiding this comment

The 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
Expand All @@ -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)

Expand All @@ -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
Expand All @@ -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 = {
Expand All @@ -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
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Não estava adicionando arestas para invoke statements, por exemplo:

  1. stack1 = class...
  2. invoke stack1.m();

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)
Expand Down Expand Up @@ -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) = {
Expand Down Expand Up @@ -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)
Expand All @@ -468,8 +519,10 @@ abstract class JSVFA extends SVFA with Analysis with FieldSensitiveness with Obj
})
// })
// }

}
}

}

def storeArrayRule(assignStmt: AssignStmt) {
Expand All @@ -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 => {
Expand Down Expand Up @@ -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
}

}
1 change: 1 addition & 0 deletions src/main/scala/br/unb/cic/soot/svfa/jimple/Statement.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ case class AssignStmt(b: Unit) extends Statement(b) {
case class InvokeStmt(b: Unit) extends Statement(b) {
val stmt = base.asInstanceOf[soot.jimple.InvokeStmt]
}

case class InvalidStmt(b: Unit) extends Statement(b)

object Statement {
Expand Down
12 changes: 12 additions & 0 deletions src/test/java/samples/AllocationFlowTest1.java
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;
}
}
11 changes: 11 additions & 0 deletions src/test/java/samples/AllocationFlowTest2.java
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;
}
}
10 changes: 10 additions & 0 deletions src/test/java/samples/Field1.java
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
}
}
10 changes: 10 additions & 0 deletions src/test/java/samples/Field2.java
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
}
}
10 changes: 10 additions & 0 deletions src/test/java/samples/Field3.java
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
}
}
Loading