From 97c4131b49d3799440c3112b2db5d370786c05c0 Mon Sep 17 00:00:00 2001 From: Matheus Barbosa Date: Wed, 22 Sep 2021 18:12:13 -0300 Subject: [PATCH] feat(#31): add stacktrace --- .../InterproceduralOverrideAssignment.java | 39 +++++++++---- .../br/unb/cic/analysis/model/Conflict.java | 23 +++++++- .../br/unb/cic/analysis/model/Statement.java | 58 +++++++++++-------- .../unb/cic/analysis/model/TraversedLine.java | 55 ++++++++++++++++++ ...duralOverridingAssignmentAnalysisTest.java | 11 ++++ .../samples/ioa/StacktraceConflictSample.java | 29 ++++++++++ 6 files changed, 179 insertions(+), 36 deletions(-) create mode 100644 src/main/java/br/unb/cic/analysis/model/TraversedLine.java create mode 100644 src/test/java/br/unb/cic/analysis/samples/ioa/StacktraceConflictSample.java diff --git a/src/main/java/br/unb/cic/analysis/ioa/InterproceduralOverrideAssignment.java b/src/main/java/br/unb/cic/analysis/ioa/InterproceduralOverrideAssignment.java index 79314071..73dd8683 100644 --- a/src/main/java/br/unb/cic/analysis/ioa/InterproceduralOverrideAssignment.java +++ b/src/main/java/br/unb/cic/analysis/ioa/InterproceduralOverrideAssignment.java @@ -5,6 +5,7 @@ import br.unb.cic.analysis.df.DataFlowAbstraction; import br.unb.cic.analysis.model.Conflict; import br.unb.cic.analysis.model.Statement; +import br.unb.cic.analysis.model.TraversedLine; import br.unb.cic.exceptions.ValueNotHandledException; import soot.*; import soot.jimple.*; @@ -28,6 +29,7 @@ public class InterproceduralOverrideAssignment extends SceneTransformer implemen private final AbstractMergeConflictDefinition definition; private final FlowSet left; private final FlowSet right; + private List stacktraceList; private final Logger logger; @@ -39,6 +41,7 @@ public InterproceduralOverrideAssignment(AbstractMergeConflictDefinition definit this.right = new ArraySparseSet<>(); this.traversedMethods = new ArrayList<>(); this.pointsToAnalysis = Scene.v().getPointsToAnalysis(); + this.stacktraceList = new ArrayList<>(); this.logger = Logger.getLogger( InterproceduralOverrideAssignment.class.getName()); @@ -95,7 +98,8 @@ protected void internalTransform(String s, Map map) { * The remaining statements of the current method that have no markup will be marked according to the flowChangeTag. * @return the result of applying the analysis considering the income abstraction (in) and the sootMethod */ - private FlowSet traverse(FlowSet in, SootMethod sootMethod, Statement.Type flowChangeTag) { + private FlowSet traverse(FlowSet in, SootMethod sootMethod, + Statement.Type flowChangeTag) { //System.out.println(sootMethod); if (this.traversedMethods.contains(sootMethod) || sootMethod.isPhantom()) { return in; @@ -107,11 +111,16 @@ private FlowSet traverse(FlowSet in, S if (body != null) { for (Unit unit : body.getUnits()) { + TraversedLine traversedLine = new TraversedLine(sootMethod, unit.getJavaSourceStartLineNumber()); + if (isTagged(flowChangeTag, unit)) { + addStackTrace(traversedLine); in = runAnalysisWithTaggedUnit(in, sootMethod, flowChangeTag, unit); } else { in = runAnalysisWithBaseUnit(in, sootMethod, flowChangeTag, unit); } + + removeStackTrace(traversedLine); } } @@ -160,16 +169,16 @@ private FlowSet runAnalysis(FlowSet in AssignStmt assignStmt = (AssignStmt) unit; if (assignStmt.containsInvokeExpr()) { - return executeCallGraph(in, flowChangeTag, unit); + return executeCallGraph(in, flowChangeTag, unit, sootMethod); } + separeteAbstraction(in); if (tagged) { Statement stmt = getStatementAssociatedWithUnit(sootMethod, unit, flowChangeTag); + setStackTraceInStmt(stmt); // logger.log(Level.INFO, () -> String.format("%s", "stmt: " + stmt.toString())); - separeteAbstraction(in); gen(in, stmt); } else { - separeteAbstraction(in); kill(in, unit); } @@ -191,7 +200,7 @@ In this case, this condition will be executed for the call to the foo() method a For builders, InvokeExpression is an instance of InvokeSpecial */ } else if (unit instanceof InvokeStmt) { - return executeCallGraph(in, flowChangeTag, unit); + return executeCallGraph(in, flowChangeTag, unit, sootMethod); } return in; @@ -210,7 +219,8 @@ private void separeteAbstraction(FlowSet in) { }); } - private FlowSet executeCallGraph(FlowSet in, Statement.Type flowChangeTag, Unit unit) { + private FlowSet executeCallGraph(FlowSet in, + Statement.Type flowChangeTag, Unit unit, SootMethod sootMethod) { CallGraph callGraph = Scene.v().getCallGraph(); Iterator edges = callGraph.edgesOutOf(unit); @@ -219,11 +229,11 @@ private FlowSet executeCallGraph(FlowSet traverseResult = traverse(in.clone(), method, stmt.getType()); flowSetList.add(traverseResult); - } FlowSet flowSetUnion = new ArraySparseSet<>(); @@ -259,9 +269,6 @@ private void gen(FlowSet in, Statement stmt) { } else if (isLefAndRightStatement(stmt)) { addConflict(stmt, stmt); - - //addStmtToList(stmt, left); - } addStmtToList(stmt, in); } @@ -359,6 +366,18 @@ private Statement getStatementAssociatedWithUnit(SootMethod sootMethod, Unit u, return createStatement(sootMethod, u, Statement.Type.IN_BETWEEN); } + private void setStackTraceInStmt(Statement stmt) { + stmt.setStacktrace(new ArrayList(this.stacktraceList)); + } + + private void addStackTrace(TraversedLine traversedLine) { + this.stacktraceList.add(traversedLine); + } + + private void removeStackTrace(TraversedLine traversedLine) { + this.stacktraceList.remove(traversedLine); + } + private boolean isBothUnitOrBothStatementFlow(Unit u, Statement.Type flowChangeTag) { if (isRightUnit(u) && isInLeftStatementFlow(flowChangeTag)) { return true; diff --git a/src/main/java/br/unb/cic/analysis/model/Conflict.java b/src/main/java/br/unb/cic/analysis/model/Conflict.java index aa911aaa..4022238b 100644 --- a/src/main/java/br/unb/cic/analysis/model/Conflict.java +++ b/src/main/java/br/unb/cic/analysis/model/Conflict.java @@ -2,6 +2,7 @@ import soot.Unit; +import java.util.List; import java.util.Objects; /** @@ -13,21 +14,26 @@ public class Conflict { protected String sourceClassName; protected String sourceMethodName; protected Integer sourceLineNumber; + protected Unit sourceUnit; + protected List sourceTraversedLine; protected String sinkClassName; protected String sinkMethodName; protected Integer sinkLineNumber; - protected Unit sourceUnit; protected Unit sinkUnit; + protected List sinkTraversedLine; + public Conflict(Statement source, Statement sink) { this.sourceClassName = source.getSootClass().getName(); this.sourceMethodName = source.getSootMethod().getName(); this.sourceLineNumber = source.getSourceCodeLineNumber(); this.sourceUnit = source.getUnit(); + this.sourceTraversedLine = source.getStacktrace(); this.sinkClassName = sink.getSootClass().getName(); this.sinkMethodName = sink.getSootMethod().getName(); this.sinkLineNumber = sink.getSourceCodeLineNumber(); this.sinkUnit = sink.getUnit(); + this.sinkTraversedLine = sink.getStacktrace(); } @Deprecated @@ -40,6 +46,7 @@ public Conflict(String sourceClassName, String sourceMethodName, Integer sourceL this.sinkLineNumber = sinkLineNumber; } + public String getSourceClassName() { return sourceClassName; } @@ -84,9 +91,19 @@ public int hashCode() { return Objects.hash(sourceClassName, sourceMethodName, sourceLineNumber, sinkClassName, sinkMethodName, sinkLineNumber); } +/* @Override + public String toString() { + return String.format("source(%s, %s, %d, %s, %s) => sink(%s, %s, %d, %s, %s)", sourceTraversedLine.get(0).getSootClass(), + sourceTraversedLine.get(0).getSootMethod(), sourceTraversedLine.get(0).getLineNumber(), sourceUnit, + sourceTraversedLine, + sinkTraversedLine.get(0).getSootClass(), sinkTraversedLine.get(0).getSootMethod(), + sinkTraversedLine.get(0).getLineNumber(), sinkUnit, sinkTraversedLine); + }*/ + @Override public String toString() { - return String.format("source(%s, %s, %d, %s) => sink(%s, %s, %d, %s)", sourceClassName, sourceMethodName, sourceLineNumber, sourceUnit, - sinkClassName, sinkMethodName, sinkLineNumber, sinkUnit); + return String.format("source(%s, %s, %d, %s, %s) => sink(%s, %s, %d, %s, %s)", sourceClassName, + sourceMethodName, sourceLineNumber, sourceUnit, sourceTraversedLine, + sinkClassName, sinkMethodName, sinkLineNumber, sinkUnit, sinkTraversedLine); } } diff --git a/src/main/java/br/unb/cic/analysis/model/Statement.java b/src/main/java/br/unb/cic/analysis/model/Statement.java index 210aff82..93699b4b 100644 --- a/src/main/java/br/unb/cic/analysis/model/Statement.java +++ b/src/main/java/br/unb/cic/analysis/model/Statement.java @@ -4,6 +4,8 @@ import soot.SootMethod; import soot.Unit; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; /** @@ -24,32 +26,42 @@ public enum Type { public static StatementBuilder builder() { if(builder == null) { - builder = new StatementBuilder(); - } - return builder; - } + builder = new StatementBuilder(); + } + return builder; + } - private SootClass sootClass; - private SootMethod sootMethod; - private Unit unit; - private Type type; - private Integer sourceCodeLineNumber; - - Statement(SootClass sootClass, SootMethod sootMethod, Unit unit, Type type, Integer sourceCodeLineNumber) { - this.sootClass = sootClass; - this.sootMethod = sootMethod; - this.unit = unit; - this.type = type; - this.sourceCodeLineNumber = sourceCodeLineNumber; - } + private SootClass sootClass; + private SootMethod sootMethod; + private Unit unit; + private Type type; + private Integer sourceCodeLineNumber; + private List traversedLine; - public SootClass getSootClass() { - return sootClass; - } + Statement(SootClass sootClass, SootMethod sootMethod, Unit unit, Type type, Integer sourceCodeLineNumber) { + this.sootClass = sootClass; + this.sootMethod = sootMethod; + this.unit = unit; + this.type = type; + this.sourceCodeLineNumber = sourceCodeLineNumber; + this.traversedLine = new ArrayList<>(); + } - public SootMethod getSootMethod() { - return sootMethod; - } + public List getStacktrace() { + return traversedLine; + } + + public void setStacktrace(List traversedLine) { + this.traversedLine = traversedLine; + } + + public SootClass getSootClass() { + return sootClass; + } + + public SootMethod getSootMethod() { + return sootMethod; + } public Unit getUnit() { return unit; diff --git a/src/main/java/br/unb/cic/analysis/model/TraversedLine.java b/src/main/java/br/unb/cic/analysis/model/TraversedLine.java new file mode 100644 index 00000000..9088dc0f --- /dev/null +++ b/src/main/java/br/unb/cic/analysis/model/TraversedLine.java @@ -0,0 +1,55 @@ +package br.unb.cic.analysis.model; + +import soot.SootClass; +import soot.SootMethod; + +public class TraversedLine { + protected SootClass sootClass; + protected SootMethod sootMethod; + protected Integer lineNumber; + + public TraversedLine(SootClass sootClass, SootMethod sootMethod, Integer lineNumber) { + this.sootClass = sootClass; + this.sootMethod = sootMethod; + this.lineNumber = lineNumber; + } + + public TraversedLine(SootMethod sootMethod, Integer lineNumber) { + this.sootClass = sootMethod.getDeclaringClass(); + this.sootMethod = sootMethod; + this.lineNumber = lineNumber; + } + + public SootClass getSootClass() { + return sootClass; + } + + public void setSootClass(SootClass sootClass) { + this.sootClass = sootClass; + } + + public SootMethod getSootMethod() { + return sootMethod; + } + + public void setSootMethod(SootMethod sootMethod) { + this.sootMethod = sootMethod; + } + + public Integer getLineNumber() { + return lineNumber; + } + + public void setLineNumber(Integer lineNumber) { + this.lineNumber = lineNumber; + } + + @Override + public String toString() { + return "Stacktrace{" + + "sootClass=" + sootClass.getShortJavaStyleName() + + ", sootMethod=" + sootMethod.getSubSignature() + + ", lineNumber=" + lineNumber + + '}'; + } +} diff --git a/src/test/java/br/unb/cic/analysis/ioa/InterproceduralOverridingAssignmentAnalysisTest.java b/src/test/java/br/unb/cic/analysis/ioa/InterproceduralOverridingAssignmentAnalysisTest.java index ed6286b6..c52c4dd8 100644 --- a/src/test/java/br/unb/cic/analysis/ioa/InterproceduralOverridingAssignmentAnalysisTest.java +++ b/src/test/java/br/unb/cic/analysis/ioa/InterproceduralOverridingAssignmentAnalysisTest.java @@ -86,6 +86,17 @@ private void configureSootOptions(List testClasses) { Options.v().set_include(getIncludeList()); } + + @Test + public void stacktraceConflictSample() { + String sampleClassPath = "br.unb.cic.analysis.samples.ioa.StacktraceConflictSample"; + AbstractMergeConflictDefinition definition = DefinitionFactory + .definition(sampleClassPath, new int[]{12}, new int[]{13}); + InterproceduralOverrideAssignment analysis = new InterproceduralOverrideAssignment(definition); + configureTest(analysis); + Assert.assertEquals(2, analysis.getConflicts().size()); + } + @Test public void subclassWithConditionalTeste() { diff --git a/src/test/java/br/unb/cic/analysis/samples/ioa/StacktraceConflictSample.java b/src/test/java/br/unb/cic/analysis/samples/ioa/StacktraceConflictSample.java new file mode 100644 index 00000000..68593263 --- /dev/null +++ b/src/test/java/br/unb/cic/analysis/samples/ioa/StacktraceConflictSample.java @@ -0,0 +1,29 @@ +package br.unb.cic.analysis.samples.ioa; + +// Conflict: [left, m():11] --> [right, m():12] +public class StacktraceConflictSample { + private int x, y; + + public void main() { + StacktraceConflictSample m = new StacktraceConflictSample(); + + m.foo(); // LEFT + m.bar(); // RIGHT + } + + private void foo() { + qux(); + System.out.println(); + y = 1; + } + + private void bar() { + x = 2; + y = 2; + } + + private void qux() { + x = 3; + System.out.println(); + } +} \ No newline at end of file