Skip to content

Commit

Permalink
Merge pull request #2137 from MarcMil/mdev
Browse files Browse the repository at this point in the history
Do not alter semantics when propagating class constants
  • Loading branch information
StevenArzt authored Jan 14, 2025
2 parents 0c81657 + ce07530 commit 8bf0272
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 4 deletions.
4 changes: 4 additions & 0 deletions src/main/java/soot/dexpler/DalvikThrowAnalysis.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import soot.NullType;
import soot.PrimType;
import soot.RefLikeType;
import soot.RefType;
import soot.Scene;
import soot.Singletons;
import soot.SootMethod;
Expand Down Expand Up @@ -297,6 +298,9 @@ public void caseClassConstant(ClassConstant c) {
// would be detected there.
//
// result = result.add(mgr.RESOLVE_CLASS_ERRORS);

// that being said, a NoClassDefFoundError is possible nonetheless.
result = result.add(RefType.v("java.lang.NoClassDefFoundError"));
}

@Override
Expand Down
108 changes: 108 additions & 0 deletions src/main/java/soot/jimple/toolkits/scalar/ConstantPropagatorUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package soot.jimple.toolkits.scalar;

import soot.Body;
import soot.FastHierarchy;
import soot.RefType;
import soot.Scene;
import soot.Trap;
import soot.Unit;
import soot.UnitPatchingChain;
import soot.Value;
import soot.ValueBox;
import soot.jimple.ClassConstant;
import soot.jimple.DefinitionStmt;
import soot.toolkits.graph.ExceptionalUnitGraph;
import soot.toolkits.graph.ExceptionalUnitGraph.ExceptionDest;

/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 2000 Patrick Lam
* %%
* 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%
*/

/**
* Contains utility methods for constant propagation
*/
public class ConstantPropagatorUtils {

/**
* Checks whether propagating <i>propagatedValue</i> from <i>defFrom</i> to <i>defTo</i> is safe.
* @param graph an exceptional unit graph
* @param propagatedValue the propagated value
* @param defFrom definition source
* @param defTo target
* @param targetBox the target box
* @return true if and only if propagation is safe w.r.t. trap handling
*/
public static boolean mayPropagate(ExceptionalUnitGraph graph, Value propagatedValue, DefinitionStmt defFrom, Unit defTo,
ValueBox targetBox) {
if (!targetBox.canContainValue(propagatedValue)) {
return false;
}
if (propagatedValue instanceof ClassConstant) {
//Class Constants can trigger a NoClassDefFoundError.
//Therefore, we must not propagate them, since we might change the semantics of the original
//program w.r.t. traps.
RefType rt = RefType.v("java.lang.NoClassDefFoundError");
Trap trap = null;
for (ExceptionDest d : graph.getExceptionDests(defFrom)) {
if (d.getThrowables().catchableAs(rt)) {
trap = d.getTrap();
break;
}
}
Body body = graph.getBody();
FastHierarchy fh = Scene.v().getOrMakeFastHierarchy();
UnitPatchingChain chain = body.getUnits();

//this is not super fast, but the exceptional unit graph is not helpful here, since
//we would need to rebuild it after propagation to reflect the changes, which would be more expensive.
for (Trap i : body.getTraps()) {
if (trap != null && i.getHandlerUnit() != trap.getHandlerUnit()) {
continue;
}
if (fh.canStoreType(rt, i.getException().getType())) {
Unit u = i.getBeginUnit();
while (u != i.getEndUnit()) {
if (u == defTo) {
//when the original code had the same handling unit, this is fine.
//if there is none, this is not fine.
return trap != null;
}
u = chain.getSuccOf(u);
}
}
}
//we have not found a trap, so the original code must not have one, either
return trap == null;
}

return true;
}

private static Unit getTrapHandler(ExceptionalUnitGraph graph, Unit def, RefType rtException) {
for (ExceptionDest d : graph.getExceptionDests(def)) {
if (d.getThrowables().catchableAs(rtException)) {
return d.getHandlerNode();
}
}
return null;
}

}
7 changes: 4 additions & 3 deletions src/main/java/soot/jimple/toolkits/scalar/CopyPropagator.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@
import soot.tagkit.SourceLnPosTag;
import soot.tagkit.Tag;
import soot.toolkits.exceptions.ThrowAnalysis;
import soot.toolkits.graph.ExceptionalUnitGraph;
import soot.toolkits.graph.ExceptionalUnitGraphFactory;
import soot.toolkits.graph.PseudoTopologicalOrderer;
import soot.toolkits.graph.UnitGraph;
import soot.toolkits.scalar.LocalDefs;

public class CopyPropagator extends BodyTransformer {
Expand Down Expand Up @@ -137,7 +137,7 @@ protected void internalTransform(Body b, String phaseName, Map<String, String> o
int fastCopyPropagationCount = 0;
int slowCopyPropagationCount = 0;

UnitGraph graph
ExceptionalUnitGraph graph
= ExceptionalUnitGraphFactory.createExceptionalUnitGraph(b, throwAnalysis, forceOmitExceptingUnitEdges);
LocalDefs localDefs = G.v().soot_toolkits_scalar_LocalDefsFactory().newLocalDefs(graph);
CPOptions options = new CPOptions(opts);
Expand Down Expand Up @@ -192,10 +192,11 @@ protected void internalTransform(Body b, String phaseName, Map<String, String> o
final Value rightOp = def.getRightOp();

if (rightOp instanceof Constant) {
if (useBox.canContainValue(rightOp)) {
if (ConstantPropagatorUtils.mayPropagate(graph, rightOp, def, u, useBox)) {
useBox.setValue(rightOp);
copyLineTags(useBox, def);
}

} else if (rightOp instanceof CastExpr) {
CastExpr ce = (CastExpr) rightOp;
if (ce.getCastType() instanceof RefLikeType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,7 @@ public void caseStringConstant(StringConstant c) {

@Override
public void caseClassConstant(ClassConstant c) {
result = result.add(RefType.v("java.lang.NoClassDefFoundError"));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import soot.dexpler.DexNullArrayRefTransformer;
import soot.dexpler.DexNullThrowTransformer;
import soot.jimple.AssignStmt;
import soot.jimple.ClassConstant;
import soot.jimple.CmpgExpr;
import soot.jimple.CmplExpr;
import soot.jimple.Constant;
Expand Down Expand Up @@ -344,7 +345,15 @@ protected void flowThrough(ConstantState in, Unit d, ConstantState out) {
Object rop = assign.getRightOp();
Constant value = null;
if (rop instanceof Constant) {
value = (Constant) rop;
//Class Constants can trigger a NoClassDefFoundError.
//Therefore, cannot not propagate them in some cases, since we might change the semantics of the original
//program w.r.t. traps.
//The normal constant propagator propagates them when they are safe to propagate.
//Implementing this here is harder,
//since we need to keep track of trap handlers at all assigns in the original code.
if (!(rop instanceof ClassConstant)) {
value = (Constant) rop;
}
} else {
if (rop instanceof Local) {
value = in.getConstant((Local) rop);
Expand Down

0 comments on commit 8bf0272

Please sign in to comment.