Skip to content

Commit

Permalink
Merge pull request #2113 from MarcMil/fixes
Browse files Browse the repository at this point in the history
Fixes for typing
  • Loading branch information
StevenArzt authored Oct 21, 2024
2 parents 8cb447c + 371d664 commit 32634a6
Show file tree
Hide file tree
Showing 15 changed files with 569 additions and 109 deletions.
200 changes: 186 additions & 14 deletions src/main/java/soot/dexpler/DexBody.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,24 @@

import soot.ArrayType;
import soot.Body;
import soot.BooleanConstant;
import soot.BooleanType;
import soot.ByteType;
import soot.DoubleType;
import soot.FloatType;
import soot.IntType;
import soot.IntegerType;
import soot.Local;
import soot.LongType;
import soot.Modifier;
import soot.NullType;
import soot.PackManager;
import soot.PhaseOptions;
import soot.PrimType;
import soot.RefLikeType;
import soot.RefType;
import soot.Scene;
import soot.ShortType;
import soot.SootClass;
import soot.SootMethod;
import soot.Trap;
Expand All @@ -96,13 +102,17 @@
import soot.dexpler.instructions.OdexInstruction;
import soot.dexpler.instructions.PseudoInstruction;
import soot.dexpler.instructions.RetypeableInstruction;
import soot.dexpler.tags.ByteOpTag;
import soot.dexpler.tags.DexplerTag;
import soot.dexpler.tags.DoubleOpTag;
import soot.dexpler.tags.FloatOpTag;
import soot.dexpler.tags.IntOpTag;
import soot.dexpler.tags.IntOrFloatOpTag;
import soot.dexpler.tags.LongOrDoubleOpTag;
import soot.dexpler.tags.ShortOpTag;
import soot.dexpler.typing.DalvikTyper;
import soot.jimple.AddExpr;
import soot.jimple.AndExpr;
import soot.jimple.ArrayRef;
import soot.jimple.AssignStmt;
import soot.jimple.BinopExpr;
Expand All @@ -117,16 +127,22 @@
import soot.jimple.FloatConstant;
import soot.jimple.IfStmt;
import soot.jimple.IntConstant;
import soot.jimple.InvokeExpr;
import soot.jimple.Jimple;
import soot.jimple.JimpleBody;
import soot.jimple.LongConstant;
import soot.jimple.MulExpr;
import soot.jimple.NeExpr;
import soot.jimple.NullConstant;
import soot.jimple.NumericConstant;
import soot.jimple.OrExpr;
import soot.jimple.RemExpr;
import soot.jimple.ShlExpr;
import soot.jimple.ShrExpr;
import soot.jimple.Stmt;
import soot.jimple.SubExpr;
import soot.jimple.UshrExpr;
import soot.jimple.XorExpr;
import soot.jimple.internal.JIdentityStmt;
import soot.jimple.toolkits.base.Aggregator;
import soot.jimple.toolkits.scalar.ConditionalBranchFolder;
Expand All @@ -140,8 +156,13 @@
import soot.jimple.toolkits.scalar.NopEliminator;
import soot.jimple.toolkits.scalar.UnconditionalBranchFolder;
import soot.jimple.toolkits.scalar.UnreachableCodeEliminator;
import soot.jimple.toolkits.typing.fast.BottomType;
import soot.jimple.toolkits.typing.fast.DefaultTypingStrategy;
import soot.jimple.toolkits.typing.fast.IHierarchy;
import soot.jimple.toolkits.typing.fast.ITypingStrategy;
import soot.jimple.toolkits.typing.fast.Integer1Type;
import soot.jimple.toolkits.typing.fast.NeedCastResult;
import soot.jimple.toolkits.typing.fast.TypePromotionUseVisitor;
import soot.options.JBOptions;
import soot.options.Options;
import soot.tagkit.LineNumberTag;
Expand Down Expand Up @@ -717,13 +738,10 @@ public Body jimplify(Body b, SootMethod m) {

// Make sure that we don't have any overlapping uses due to returns
DexReturnInliner.v().transform(jBody);
handleKnownDexTypes(b, jimple);

new SharedInitializationLocalSplitter(DalvikThrowAnalysis.v()).transform(jBody);

// split first to find undefined uses
getLocalSplitter().transform(jBody);

// Remove dead code and the corresponding locals before assigning types
getUnreachableCodeEliminator().transform(jBody);
DeadAssignmentEliminator.v().transform(jBody);
Expand Down Expand Up @@ -807,6 +825,8 @@ public Body jimplify(Body b, SootMethod m) {
}
DexFillArrayDataTransformer.v().transform(jBody);
// SharedInitializationLocalSplitter destroys the inserted casts, so we have to reintroduce them
getLocalSplitter().transform(jBody);

MultiMap<Local, Type> maybetypeConstraints = new HashMultiMap<>();
handleKnownDexTypes(b, jimple);
handleKnownDexArrayTypes(b, jimple, maybetypeConstraints);
Expand All @@ -819,6 +839,61 @@ public Body jimplify(Body b, SootMethod m) {
}

new soot.jimple.toolkits.typing.fast.TypeResolver(jBody) {
protected soot.jimple.toolkits.typing.fast.TypePromotionUseVisitor createTypePromotionUseVisitor(JimpleBody jb,
soot.jimple.toolkits.typing.fast.Typing tg) {
return new TypePromotionUseVisitor(jb, tg) {
protected boolean allowConversion(Type ancestor, Type child) {
if (ancestor == child) {
return true;
}
if ((ancestor instanceof IntegerType || ancestor instanceof FloatType)
&& (child instanceof IntegerType || child instanceof FloatType)) {
return true;
}
if ((ancestor instanceof LongType || ancestor instanceof DoubleType)
&& (child instanceof LongType || child instanceof DoubleType)) {
return true;
}
return super.allowConversion(ancestor, child);
}

public Type promote(Type tlow, Type thigh) {
if (thigh instanceof BooleanType && tlow instanceof IntegerType) {
//Well... in Android's dex code, 0 = false and everything else is true
//While the compiler should never generate such code, there can be found code like this in the wild.
//And Android accepts it!
//Thus, we allow the type promotion and then correct the boolean constants
return thigh;
}
if (tlow instanceof IntegerType) {
if (thigh instanceof FloatType || thigh instanceof IntType) {
return thigh;
}
}
return super.promote(tlow, thigh);

}
};

}

protected soot.jimple.toolkits.typing.fast.BytecodeHierarchy createBytecodeHierarchy() {
return new soot.jimple.toolkits.typing.fast.BytecodeHierarchy() {
public java.util.Collection<Type> lcas(Type a, Type b, boolean useWeakObjectType) {
Collection<Type> s = super.lcas(a, b, useWeakObjectType);
if (s.isEmpty()) {
//when we merge a null constant and anything non-primitive, we use the non-primitive type
if (a instanceof Integer1Type && b instanceof RefLikeType) {
return Collections.singleton(b);
}
if (b instanceof Integer1Type && a instanceof RefLikeType) {
return Collections.singleton(a);
}
}
return s;
}
};
}

@Override
protected Collection<Type> reduceToAllowedTypesForLocal(Collection<Type> lcas, Local v) {
Expand Down Expand Up @@ -850,6 +925,49 @@ protected soot.jimple.toolkits.typing.fast.ITypingStrategy getTypingStrategy() {
protected CastInsertionUseVisitor createCastInsertionUseVisitor(soot.jimple.toolkits.typing.fast.Typing tg,
soot.jimple.toolkits.typing.fast.IHierarchy h, boolean countOnly) {
return new CastInsertionUseVisitor(countOnly, jBody, tg, h) {

protected NeedCastResult needCast(Type target, Type from, IHierarchy h) {
NeedCastResult r = super.needCast(target, from, h);
if (r == NeedCastResult.NEEDS_CAST) {
if (target instanceof IntType || target instanceof FloatType) {
if (from instanceof IntegerType || from instanceof FloatType) {
return NeedCastResult.DISCOURAGED_TARGET_TYPE;
}
}
if (target instanceof LongType || target instanceof DoubleType) {
if (from instanceof IntegerType || from instanceof LongType || from instanceof DoubleType) {
return NeedCastResult.DISCOURAGED_TARGET_TYPE;
}
}
return r;
}

//we need to this since some types are final already. Otherwise,
//we get no casts at all.
if (target instanceof PrimType && from instanceof PrimType) {
if (!from.isAllowedInFinalCode()) {
from = from.getDefaultFinalType();
}
if (target.isAllowedInFinalCode()) {
if (target == from) {
return NeedCastResult.DOESNT_NEED_CAST;
}
if (target instanceof IntType || target instanceof FloatType) {
if (from instanceof IntegerType || from instanceof FloatType) {
return NeedCastResult.DISCOURAGED_TARGET_TYPE;
}
}
if (target instanceof LongType || target instanceof DoubleType) {
if (from instanceof IntegerType || from instanceof LongType || from instanceof DoubleType) {
return NeedCastResult.DISCOURAGED_TARGET_TYPE;
}
}
return NeedCastResult.NEEDS_CAST;
}
}
return NeedCastResult.DOESNT_NEED_CAST;
}

@Override
public Value visit(Value op, Type useType, Stmt stmt, boolean checkOnly) {
if (op instanceof LongConstant && useType instanceof DoubleType) {
Expand Down Expand Up @@ -966,7 +1084,6 @@ public Value visit(Value op, Type useType, Stmt stmt, boolean checkOnly) {
// again lead to unused locals which we have to remove.
LocalPacker.v().transform(jBody);
UnusedLocalEliminator.v().transform(jBody);
PackManager.v().getTransform("jb.lns").apply(jBody);

// Some apps reference static fields as instance fields. We fix this
// on the fly.
Expand Down Expand Up @@ -1028,13 +1145,32 @@ public Value visit(Value op, Type useType, Stmt stmt, boolean checkOnly) {
for (Unit u : jBody.getUnits()) {

if (u instanceof AssignStmt) {
AssignStmt ass = (AssignStmt) u;
if (ass.getRightOp() instanceof CastExpr) {
CastExpr c = (CastExpr) ass.getRightOp();
final AssignStmt ass = (AssignStmt) u;
final Value rop = ass.getRightOp();
if (rop instanceof CastExpr) {
CastExpr c = (CastExpr) rop;
if (c.getType() instanceof NullType) {
ass.setRightOp(nullConstant);
}
}
if (rop instanceof IntConstant) {
if (ass.getLeftOp().getType() instanceof BooleanType) {
ass.setRightOp(fixBooleanConstant((IntConstant) rop));
}
}

}
Stmt s = (Stmt) u;
if (s.containsInvokeExpr()) {
InvokeExpr inv = s.getInvokeExpr();
for (int p = 0; p < inv.getArgCount(); p++) {
if (inv.getMethodRef().getParameterType(p) instanceof BooleanType) {
Value arg = inv.getArg(p);
if (arg instanceof IntConstant) {
inv.setArg(p, fixBooleanConstant((IntConstant) arg));
}
}
}
}
if (u instanceof DefinitionStmt) {
DefinitionStmt def = (DefinitionStmt) u;
Expand Down Expand Up @@ -1067,7 +1203,7 @@ public Value visit(Value op, Type useType, Stmt stmt, boolean checkOnly) {
//
for (Local l : jBody.getLocals()) {
Type t = l.getType();
if (t instanceof NullType) {
if (t instanceof NullType || t instanceof BottomType) {
l.setType(objectType);
}
}
Expand All @@ -1083,6 +1219,16 @@ public Value visit(Value op, Type useType, Stmt stmt, boolean checkOnly) {
return jBody;
}

/**
* In Dex, every int is a valid boolean.
* 0 = false and everything else = true.
* @param arg
* @return
*/
private static BooleanConstant fixBooleanConstant(IntConstant arg) {
return BooleanConstant.v(arg.value != 0);
}

/**
* For non-object array instructions, we know from the bytecode already what the types are, or at least we can reduce it to
* two possibilities (int/float or float/double).
Expand Down Expand Up @@ -1169,19 +1315,29 @@ private void handleKnownDexTypes(Body b, final Jimple jimple) {
if (rop instanceof BinopExpr) {
boolean isDouble = u.hasTag(DoubleOpTag.NAME);
boolean isFloat = u.hasTag(FloatOpTag.NAME);
boolean isInt = u.hasTag(IntOpTag.NAME);
boolean isShort = u.hasTag(ShortOpTag.NAME);
boolean isByte = u.hasTag(ByteOpTag.NAME);
if (rop instanceof AddExpr || rop instanceof SubExpr || rop instanceof MulExpr || rop instanceof DivExpr
|| rop instanceof RemExpr) {
|| rop instanceof RemExpr || rop instanceof XorExpr || rop instanceof UshrExpr || rop instanceof ShrExpr
|| rop instanceof ShlExpr || rop instanceof AndExpr || rop instanceof OrExpr) {
Type t = null;
if (isDouble) {
t = DoubleType.v();
} else if (isFloat) {
t = FloatType.v();
} else if (isInt) {
t = IntType.v();
} else if (isShort) {
t = ShortType.v();
} else if (isByte) {
t = ByteType.v();
}
if (t != null) {
Local l = createOrGetVariableOfType(b, convSingle, t);
Value prev = def.getLeftOp();
def.setLeftOp(l);
units.insertAfter(jimple.newAssignStmt(prev, jimple.newCastExpr(l, t)), u);
units.insertAfter(jimple.newAssignStmt(prev, l), u);
}
}
BinopExpr bop = (BinopExpr) rop;
Expand All @@ -1205,8 +1361,7 @@ private void handleKnownDexTypes(Body b, final Jimple jimple) {
convDouble[idxConvVar] = jimple.newLocal(freshLocalName("lclConvToDouble" + idxConvVar), DoubleType.v());
b.getLocals().add(convDouble[idxConvVar]);
}
units.insertBefore(
jimple.newAssignStmt(convDouble[idxConvVar], jimple.newCastExpr(cmp.getValue(), DoubleType.v())), u);
units.insertBefore(jimple.newAssignStmt(convDouble[idxConvVar], cmp.getValue()), u);
cmp.setValue(convDouble[idxConvVar]);
idxConvVar++;
}
Expand All @@ -1216,8 +1371,7 @@ private void handleKnownDexTypes(Body b, final Jimple jimple) {
convFloat[idxConvVar] = jimple.newLocal(freshLocalName("lclConvToFloat" + idxConvVar), FloatType.v());
b.getLocals().add(convFloat[idxConvVar]);
}
units.insertBefore(
jimple.newAssignStmt(convFloat[idxConvVar], jimple.newCastExpr(cmp.getValue(), FloatType.v())), u);
units.insertBefore(jimple.newAssignStmt(convFloat[idxConvVar], cmp.getValue()), u);
cmp.setValue(convFloat[idxConvVar]);
idxConvVar++;
}
Expand All @@ -1227,6 +1381,24 @@ private void handleKnownDexTypes(Body b, final Jimple jimple) {
}

}
Stmt s = (Stmt) u;
if (s.containsInvokeExpr()) {
InvokeExpr inv = s.getInvokeExpr();
for (int pidx = 0; pidx < inv.getArgCount(); pidx++) {
Value arg = inv.getArg(pidx);
if (arg instanceof Constant) {
Type t = inv.getMethodRef().getParameterType(pidx);
if (t instanceof DoubleType && arg instanceof LongConstant) {
long vVal = ((LongConstant) arg).value;
inv.setArg(pidx, DoubleConstant.v(Double.longBitsToDouble(vVal)));
}
if (t instanceof FloatType && arg instanceof IntConstant) {
int vVal = ((IntConstant) arg).value;
inv.setArg(pidx, FloatConstant.v(Float.intBitsToFloat(vVal)));
}
}
}
}
u = units.getSuccOf(u);
}
for (Unit u1 : units) {
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/soot/jimple/internal/JEqExpr.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package soot.jimple.internal;

import soot.BooleanType;

/*-
* #%L
* Soot - a J*va Optimization Framework
Expand Down Expand Up @@ -46,6 +48,11 @@ public void apply(Switch sw) {
((ExprSwitch) sw).caseEqExpr(this);
}

@Override
public Type getType() {
return BooleanType.v();
}

@Override
protected Unit makeBafInst(Type opType) {
throw new RuntimeException("unsupported conversion: " + this);
Expand Down
Loading

0 comments on commit 32634a6

Please sign in to comment.