Skip to content

Commit

Permalink
fix the Shimple initialization bug for most test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-hoffman committed Jun 25, 2021
1 parent 63dd799 commit b1c1dab
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@
import soot.jimple.RemExpr;
import soot.jimple.Stmt;
import soot.options.Options;
import soot.shimple.ShimpleBody;
import soot.toolkits.graph.ExceptionalUnitGraph;
import soot.toolkits.graph.FullExceptionalUnitGraph;
import soot.toolkits.scalar.LocalDefs;
import soot.toolkits.scalar.LocalUses;
import soot.toolkits.scalar.UnitValueBoxPair;
Expand Down Expand Up @@ -237,7 +240,8 @@ protected void internalTransform(Body b, String phaseName, Map<String, String> o
// Add all the statements which are used to compute values
// for the essential statements, recursively

final LocalDefs localDefs = G.v().soot_toolkits_scalar_LocalDefsFactory().newLocalDefs(b);
final LocalDefs localDefs = G.v().soot_toolkits_scalar_LocalDefsFactory()
.newLocalDefs(b instanceof ShimpleBody ? new FullExceptionalUnitGraph(b) : new ExceptionalUnitGraph(b));

if (!allEssential) {
Set<Unit> essential = new HashSet<Unit>(units.size());
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/soot/shimple/DefaultShimpleFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import soot.toolkits.graph.DominatorsFinder;
import soot.toolkits.graph.ExceptionalBlockGraph;
import soot.toolkits.graph.ExceptionalUnitGraph;
import soot.toolkits.graph.FullExceptionalUnitGraph;
import soot.toolkits.graph.HashReversibleGraph;
import soot.toolkits.graph.ReversibleGraph;
import soot.toolkits.graph.SimpleDominatorsFinder;
Expand Down Expand Up @@ -144,7 +145,7 @@ public UnitGraph getUnitGraph() {
if (ug == null) {
Body body = getBody();
UnreachableCodeEliminator.v().transform(body);
ug = new ExceptionalUnitGraph(body);
ug = new FullExceptionalUnitGraph(body);
this.ug = ug;
}
return ug;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ protected Map<Unit, Collection<ExceptionDest>> buildExceptionDests(ThrowAnalysis
* @return a <code>Map</code> which whose contents are equivalent to the input <code>map</code>, plus the information that
* <code>u</code> throws <code>caught</code> to <code>t</code>.
*/
private Map<Unit, Collection<ExceptionDest>> addDestToMap(Map<Unit, Collection<ExceptionDest>> map, Unit u, Trap t,
protected Map<Unit, Collection<ExceptionDest>> addDestToMap(Map<Unit, Collection<ExceptionDest>> map, Unit u, Trap t,
ThrowableSet caught) {
Collection<ExceptionDest> dests = (map == null ? null : map.get(u));
if (dests == null) {
Expand Down
96 changes: 96 additions & 0 deletions src/main/java/soot/toolkits/graph/FullExceptionalUnitGraph.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package soot.toolkits.graph;

/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 2021 Timothy Hoffman
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
* #L%
*/
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;

import soot.Body;
import soot.RefType;
import soot.Trap;
import soot.Unit;
import soot.toolkits.exceptions.PedanticThrowAnalysis;
import soot.toolkits.exceptions.ThrowAnalysis;
import soot.toolkits.exceptions.ThrowableSet;
import soot.util.Chain;

/**
* Extension of {@link ExceptionalUnitGraph} that aligns more closely with the representation used by the JVM bytecode
* verifier. The standard {@link ExceptionalUnitGraph} will not add an exception edge for an exception table entry if an
* earlier entry already caught a broader exception type (i.e. the edge for the later entry will never actually execute
* during runtime). However, the JVM bytecode verifier considers all exceptional edges verbatim from the exception table and
* thus, may consider more possible paths in the CFG. Furthermore, this graph uses a {@link PedanticThrowAnalysis} to ensure
* that all Units covered by an exception table entry will have an edge to the exception handler which forces phi-node
* removal to back-propagate assignments all the way back to their original location to avoid "uninitialized register" errors
* from the JVM bytecode verifier.
*
* @author Timothy Hoffman
*/
public class FullExceptionalUnitGraph extends ExceptionalUnitGraph {

public FullExceptionalUnitGraph(Body body) {
super(body);
// Set the 'omitExceptingUnitEdges' parameter to false and use a ThrowAnalysis
// based on the PedanticThrowAnalysis so that all units (except for AssignStmt)
// will have an edge into exception handler blocks.
initialize(PedanticThrowAnalysis.v(), false);
}

@Override
protected Map<Unit, Collection<ExceptionDest>> buildExceptionDests(ThrowAnalysis throwAnalysis) {
// Identical to the original except it doesn't track the uncaught
// throwables when multiple Traps cover the same Unit. That way, the full
// effect of all traps is reflected in the graph, even if some edges
// will never be used because an earlier trap subsumes a later one.
//
Map<Unit, Collection<ExceptionDest>> result = null;

final Chain<Trap> traps = body.getTraps();
if (!traps.isEmpty()) {
final ThrowableSet EMPTY = ThrowableSet.Manager.v().EMPTY;
final Chain<Unit> units = body.getUnits();

// Record the caught exceptions.
for (Trap trap : traps) {
RefType catcher = trap.getException().getType();
for (Iterator<Unit> it = units.iterator(trap.getBeginUnit(), units.getPredOf(trap.getEndUnit())); it.hasNext();) {
Unit unit = it.next();
ThrowableSet thrownSet = throwAnalysis.mightThrow(unit);
ThrowableSet.Pair catchableAs = thrownSet.whichCatchableAs(catcher);
if (!EMPTY.equals(catchableAs.getCaught())) {
result = addDestToMap(result, unit, trap, catchableAs.getCaught());
} else {
assert (thrownSet.equals(catchableAs.getUncaught())) :
"ExceptionalUnitGraph.buildExceptionDests(): "
+ "catchableAs.caught == EMPTY, but catchableAs.uncaught != thrownSet" + System.getProperty("line.separator")
+ body.getMethod().getSubSignature() + " Unit: " + unit.toString() + System.getProperty("line.separator")
+ " catchableAs.getUncaught() == " + catchableAs.getUncaught().toString()
+ System.getProperty("line.separator") + " thrownSet == " + thrownSet.toString();
}
}
}
}
return result == null ? Collections.emptyMap() : result;
}
}

0 comments on commit b1c1dab

Please sign in to comment.