Skip to content

An error in function DynamicControlFlowGraph - matchStatementInstanceToClosestTraceLine #40

@Aric3

Description

@Aric3

Hi @khaled-e-a,

I’m trying to run Slicer4J on the Defects4J Math-83 buggy version. I’ve carefully followed the README and am using the Python script slicer4j.py to run the tool.

Here is the command I’m using:

python3 slicer4j.py \
  -j /root/workspace/Slicer4J/benchmarks/Math_83b/target/commons-math-2.1-SNAPSHOT.jar \
  -o /root/workspace/slice-results/Math_83b \
  -b org.apache.commons.math.optimization.linear.SimplexTableau:357 \
  -v coefficients \
  -tc org.apache.commons.math.optimization.linear.SimplexSolverTest \
  -tm testMath286 \
  -dep /root/workspace/Slicer4J/benchmarks/Math_83b/target/test-classes/:/root/workspace/Slicer4J/benchmarks/Math_83b/target/dependency

I believe this command is correct because a similar one works for Lang-11, for example:

python3 slicer4j.py \
  -j /root/workspace/Slicer4J/benchmarks/Lang_11b/target/commons-lang3-3.2-SNAPSHOT.jar \
  -o /root/workspace/slice-results/Lang_11b \
  -b org.apache.commons.lang3.RandomStringUtils:253 \
  -v gap \
  -tc org.apache.commons.lang3.RandomStringUtilsTest \
  -tm testLANG807 \
  -dep /root/workspace/Slicer4J/benchmarks/Lang_11b/target/test-classes/:/root/workspace/Slicer4J/benchmarks/Lang_11b/target/dependency

However, in the case of Math-83, the DFG (Dynamic Flow Graph) is not created, and the program throws a NullPointerException. Below is the output from the slice-file.log:

Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/root/workspace/Slicer4J/Slicer4J/target/slicer4j-jar-with-dependencies.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/root/workspace/Slicer4J/Slicer4J/target/lib/slf4j-simple-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory]
[main] INFO Slicer - main (216): Started Slicer4J
[main] INFO Slicer - main (261): Reading trace
[main] INFO Parser - expandTrace (102): Abs path for static-log /root/workspace/slice-results/Math_83b/static-log.log
[main] INFO Parser - expandTrace (156): Done parsing
[main] WARN Parser - readFile (66): Writing out trace file is disabled!
[main] INFO Slicer - main (266): Started graph construction
[main] INFO DynamicControlFlowGraph - createDCFG (86): Trace size: 3615
[main] INFO DynamicControlFlowGraph - createDCFG (96): Progress: 0/3615 (0), time: 0.0
[main] WARN DynamicControlFlowGraph - matchStatementInstanceToClosestTraceLine (249): Cannot create instruction 14800, <org.apache.commons.math.optimization.linear.SimplexTableau: void initialize()>, goto [?= sb = new java.lang.StringBuilder], 1
[main] INFO Slicer - main (270): Finished graph construction
[main] INFO Slicer - setBackwardSlicePositions (125): backwardSlicePositions: 3563-3564-3565-3603-3610
[main] INFO SliceJava - slice (47): Next slice: 3563, org.apache.commons.math.optimization.RealPointValuePair getSolution(), org.apache.commons.math.optimization.linear.SimplexTableau, $stack16 = new org.apache.commons.math.optimization.RealPointValuePair:THREAD:1:LINENO:357:FILE:org.apache.commons.math.optimization.linear.SimplexTableau
[main] INFO SliceJava - slice (48): Current slice size: 0
Exception in thread "main" java.lang.NullPointerException
	at ca.ubc.ece.resess.slicer.dynamic.slicer4j.datadependence.DynamicHeapAnalysis.getAp(DynamicHeapAnalysis.java:80)
	at ca.ubc.ece.resess.slicer.dynamic.slicer4j.datadependence.DynamicHeapAnalysis.reachingDefinitionsPrecomp(DynamicHeapAnalysis.java:147)
	at ca.ubc.ece.resess.slicer.dynamic.slicer4j.datadependence.DynamicHeapAnalysis.reachingDefinitionsNew(DynamicHeapAnalysis.java:184)
	at ca.ubc.ece.resess.slicer.dynamic.slicer4j.SliceJava.getDataDependence(SliceJava.java:73)
	at ca.ubc.ece.resess.slicer.dynamic.core.slicer.SliceMethod.slice(SliceMethod.java:108)
	at ca.ubc.ece.resess.slicer.dynamic.slicer4j.SliceJava.slice(SliceJava.java:49)
	at ca.ubc.ece.resess.slicer.dynamic.slicer4j.Slicer.slice(Slicer.java:389)
	at ca.ubc.ece.resess.slicer.dynamic.slicer4j.Slicer.main(Slicer.java:363)

I searched the function matchStatementInstanceToClosestTraceLine and found the following code responsible for printing that warning:

    private StatementInstance matchStatementInstanceToClosestTraceLine(SootMethod mt, Map<String, List<Unit>> unitString,
                    TraceStatement traceStatement, int lineNumber) {

        int leastDistance = Integer.MAX_VALUE;
        int lineDistance = Integer.MAX_VALUE;
        String second = traceStatement.getInstruction();
        Unit closestUnit = null;
        for(String us: unitString.keySet()) {
            String first = us;
            if (first.contains("if") && first.contains("goto")) {
                first = first.substring(0, first.indexOf("goto"));
            }
            if (second.contains("if") && second.contains("goto")) {
                second = second.substring(0, second.indexOf("goto"));
            }
            if (StringUtils.getCommonPrefix(first, second).length() > 0) {
                int threshold = Math.min(first.length(), second.length())/2;
                int distance = (new LevenshteinDistance(threshold)).apply(first, second);
                if (distance == -1) {
                    distance = threshold;
                }
                if (distance <= leastDistance) {
                    List<Unit> units = unitString.get(us);
                    Unit potentialUnit;
                    if (units.size() == 1) {
                        potentialUnit = units.get(0);
                    } else {
                        int idx = getClosestUnitByLineNumber(units, Math.toIntExact(traceStatement.getSourceLine()));
                        potentialUnit = units.get(idx);
                    }
                    int curDistance = Math.abs(Math.toIntExact(traceStatement.getSourceLine()) - potentialUnit.getJavaSourceStartLineNumber());
                    if(curDistance < lineDistance){
                        closestUnit = potentialUnit;
                        leastDistance = distance;
                        lineDistance = curDistance;
                    }
                }
            }
        }
        StatementInstance createdStatement = null;
        if (closestUnit != null) {
            createdStatement = new StatementInstance(mt, closestUnit, lineNumber, traceStatement.getThreadId(), traceStatement.getFieldAddr(), closestUnit.getJavaSourceStartLineNumber(), mt.getDeclaringClass().getFilePath());
            addStatement(createdStatement);
        } else {
            AnalysisLogger.warn(true, "Cannot create instruction {}", traceStatement);
        }
        return createdStatement;
    }

Statement AnalysisLogger.warn(true, "Cannot create instruction {}", traceStatement); print the message.

Unfortunately, I do not fully understand the logic inside this function, especially how it matches the trace statements and what could cause it to fail to create a StatementInstance.

Questions: Could this failure to create a matching instruction be the root cause of the NullPointerException later?
Thanks in advance for your help!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions