Skip to content

Commit

Permalink
fix: correct rollback if type update failed (#2090)
Browse files Browse the repository at this point in the history
  • Loading branch information
skylot committed Feb 10, 2024
1 parent a3a4fab commit ecb8abb
Show file tree
Hide file tree
Showing 41 changed files with 1,570 additions and 917 deletions.
4 changes: 4 additions & 0 deletions jadx-core/src/main/java/jadx/core/Jadx.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import jadx.core.dex.visitors.shrink.CodeShrinkVisitor;
import jadx.core.dex.visitors.ssa.SSATransform;
import jadx.core.dex.visitors.typeinference.FinishTypeInference;
import jadx.core.dex.visitors.typeinference.FixTypesVisitor;
import jadx.core.dex.visitors.typeinference.TypeInferenceVisitor;
import jadx.core.dex.visitors.usage.UsageInfoVisitor;
import jadx.core.utils.exceptions.JadxRuntimeException;
Expand Down Expand Up @@ -141,7 +142,9 @@ public static List<IDexTreeVisitor> getRegionsModePasses(JadxArgs args) {
if (args.isDebugInfo()) {
passes.add(new DebugInfoApplyVisitor());
}
passes.add(new FixTypesVisitor());
passes.add(new FinishTypeInference());

if (args.getUseKotlinMethodsForVarNames() != JadxArgs.UseKotlinMethodsForVarNames.DISABLE) {
passes.add(new ProcessKotlinInternals());
}
Expand Down Expand Up @@ -216,6 +219,7 @@ public static List<IDexTreeVisitor> getSimpleModePasses(JadxArgs args) {
if (args.isDebugInfo()) {
passes.add(new DebugInfoApplyVisitor());
}
passes.add(new FixTypesVisitor());
passes.add(new FinishTypeInference());
passes.add(new CodeRenameVisitor());
passes.add(new DeboxingVisitor());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Objects;

import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.utils.InsnUtils;
import jadx.core.utils.Utils;
Expand All @@ -23,6 +24,10 @@ public void updateIndex(Object index) {
this.index = index;
}

public ArgType getIndexAsType() {
return (ArgType) index;
}

@Override
public IndexInsnNode copy() {
return copyCommonParams(new IndexInsnNode(insnType, index, getArgsCount()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,6 @@ public boolean isSame(InsnNode obj) {

@Override
public String toString() {
return baseString() + " type: " + type + " call: " + mth + attributesString();
return baseString() + " " + type + " call: " + mth + attributesString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
import jadx.core.utils.exceptions.JadxRuntimeException;

/**
* Instruction argument,
* argument can be register, literal or instruction
* Instruction argument.
* Can be: register, literal, instruction or name
*/
public abstract class InsnArg extends Typed {

Expand Down Expand Up @@ -209,7 +209,20 @@ public static InsnArg wrapArg(InsnNode insn) {
}

public boolean isZeroLiteral() {
return isLiteral() && (((LiteralArg) this)).getLiteral() == 0;
return false;
}

public boolean isZeroConst() {
if (isZeroLiteral()) {
return true;
}
if (isInsnWrap()) {
InsnNode wrapInsn = ((InsnWrapArg) this).getWrapInsn();
if (wrapInsn.getType() == InsnType.CONST) {
return wrapInsn.getArg(0).isZeroLiteral();
}
}
return false;
}

public boolean isFalse() {
Expand Down Expand Up @@ -265,6 +278,9 @@ public boolean isSameConst(InsnArg other) {
}

public boolean isSameVar(RegisterArg arg) {
if (arg == null) {
return false;
}
if (isRegister()) {
return ((RegisterArg) this).sameRegAndSVar(arg);
}
Expand All @@ -280,4 +296,8 @@ protected final <T extends InsnArg> T copyCommonParams(T copy) {
public InsnArg duplicate() {
return this;
}

public String toShortString() {
return this.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ public boolean isLiteral() {
return true;
}

@Override
public boolean isZeroLiteral() {
return literal == 0;
}

public boolean isInteger() {
switch (type.getPrimitiveType()) {
case INT:
Expand Down Expand Up @@ -125,6 +130,11 @@ public boolean equals(Object o) {
return literal == that.literal && getType().equals(that.getType());
}

@Override
public String toShortString() {
return Long.toString(literal);
}

@Override
public String toString() {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ public boolean equals(Object o) {
return name.equals(((NamedArg) o).name);
}

@Override
public String toShortString() {
return name;
}

@Override
public String toString() {
return '(' + name + ' ' + type + ')';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,16 @@ public boolean equals(Object obj) {
&& Objects.equals(sVar, other.getSVar());
}

@Override
public String toShortString() {
StringBuilder sb = new StringBuilder();
sb.append("r").append(regNum);
if (sVar != null) {
sb.append('v').append(sVar.getVersion());
}
return sb.toString();
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
Expand Down
67 changes: 38 additions & 29 deletions jadx-core/src/main/java/jadx/core/dex/instructions/args/SSAVar.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
Expand All @@ -23,9 +24,12 @@
import jadx.core.utils.StringUtils;
import jadx.core.utils.exceptions.JadxRuntimeException;

public class SSAVar {
public class SSAVar implements Comparable<SSAVar> {
private static final Logger LOG = LoggerFactory.getLogger(SSAVar.class);

private static final Comparator<SSAVar> SSA_VAR_COMPARATOR =
Comparator.comparingInt(SSAVar::getRegNum).thenComparingInt(SSAVar::getVersion);

private final int regNum;
private final int version;

Expand Down Expand Up @@ -256,34 +260,6 @@ public boolean isCodeVarSet() {
return codeVar != null;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof SSAVar)) {
return false;
}
SSAVar ssaVar = (SSAVar) o;
return regNum == ssaVar.regNum && version == ssaVar.version;
}

@Override
public int hashCode() {
return 31 * regNum + version;
}

public String toShortString() {
return "r" + regNum + 'v' + version;
}

@Override
public String toString() {
return toShortString()
+ (StringUtils.notEmpty(getName()) ? " '" + getName() + "' " : "")
+ ' ' + typeInfo.getType();
}

public String getDetailedVarInfo(MethodNode mth) {
Set<ArgType> types = new HashSet<>();
Set<String> names = Collections.emptySet();
Expand Down Expand Up @@ -323,4 +299,37 @@ public String getDetailedVarInfo(MethodNode mth) {
}
return sb.toString();
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof SSAVar)) {
return false;
}
SSAVar ssaVar = (SSAVar) o;
return regNum == ssaVar.regNum && version == ssaVar.version;
}

@Override
public int hashCode() {
return 31 * regNum + version;
}

@Override
public int compareTo(@NotNull SSAVar o) {
return SSA_VAR_COMPARATOR.compare(this, o);
}

public String toShortString() {
return "r" + regNum + 'v' + version;
}

@Override
public String toString() {
return toShortString()
+ (StringUtils.notEmpty(getName()) ? " '" + getName() + "' " : "")
+ ' ' + typeInfo.getType();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import jadx.core.dex.visitors.typeinference.TypeInferenceVisitor;
import jadx.core.utils.InsnRemover;
import jadx.core.utils.exceptions.JadxException;
import jadx.core.utils.exceptions.JadxRuntimeException;

@JadxVisitor(
name = "Constants Inline",
Expand Down Expand Up @@ -73,8 +74,7 @@ private static void checkInsn(MethodNode mth, InsnNode insn, List<InsnNode> toRe
if (!constArg.isLiteral()) {
return;
}
long lit = ((LiteralArg) constArg).getLiteral();
if (lit == 0 && forbidNullInlines(sVar)) {
if (constArg.isZeroLiteral() && forbidNullInlines(sVar)) {
// all usages forbids inlining
return;
}
Expand Down Expand Up @@ -134,20 +134,15 @@ private static boolean forbidNullInlines(SSAVar sVar) {
}

private static boolean forbidNullArgInline(InsnNode insn, RegisterArg useArg) {
switch (insn.getType()) {
case MOVE:
case CAST:
case CHECK_CAST:
// result is null, chain checks
return forbidNullInlines(insn.getResult().getSVar());

default:
if (!canUseNull(insn, useArg)) {
useArg.add(AFlag.DONT_INLINE_CONST);
return true;
}
return false;
if (insn.getType() == InsnType.MOVE) {
// result is null, chain checks
return forbidNullInlines(insn.getResult().getSVar());
}
if (!canUseNull(insn, useArg)) {
useArg.add(AFlag.DONT_INLINE_CONST);
return true;
}
return false;
}

private static boolean canUseNull(InsnNode insn, RegisterArg useArg) {
Expand Down Expand Up @@ -269,9 +264,7 @@ private static boolean replaceArg(MethodNode mth, RegisterArg arg, InsnArg const
fieldNode.addUseIn(mth);
}
} else {
if (needExplicitCast(useInsn, litArg)) {
litArg.add(AFlag.EXPLICIT_PRIMITIVE_TYPE);
}
addExplicitCast(useInsn, litArg);
}
} else {
if (!useInsn.replaceArg(arg, constArg.duplicate())) {
Expand All @@ -282,18 +275,33 @@ private static boolean replaceArg(MethodNode mth, RegisterArg arg, InsnArg const
return true;
}

private static boolean needExplicitCast(InsnNode insn, LiteralArg arg) {
private static void addExplicitCast(InsnNode insn, LiteralArg arg) {
if (insn instanceof BaseInvokeNode) {
BaseInvokeNode callInsn = (BaseInvokeNode) insn;
MethodInfo callMth = callInsn.getCallMth();
int offset = callInsn.getFirstArgOffset();
int argIndex = insn.getArgIndex(arg);
ArgType argType = callMth.getArgumentsTypes().get(argIndex - offset);
if (argType.isPrimitive()) {
arg.setType(argType);
return argType.equals(ArgType.BYTE);
if (callInsn.getInstanceArg() == arg) {
// instance arg is null, force cast
if (!arg.isZeroLiteral()) {
throw new JadxRuntimeException("Unexpected instance arg in invoke");
}
ArgType castType = callMth.getDeclClass().getType();
InsnNode castInsn = new IndexInsnNode(InsnType.CAST, castType, 1);
castInsn.addArg(arg);
castInsn.add(AFlag.EXPLICIT_CAST);
InsnArg wrapCast = InsnArg.wrapArg(castInsn);
wrapCast.setType(castType);
insn.replaceArg(arg, wrapCast);
} else {
int offset = callInsn.getFirstArgOffset();
int argIndex = insn.getArgIndex(arg);
ArgType argType = callMth.getArgumentsTypes().get(argIndex - offset);
if (argType.isPrimitive()) {
arg.setType(argType);
if (argType.equals(ArgType.BYTE)) {
arg.add(AFlag.EXPLICIT_PRIMITIVE_TYPE);
}
}
}
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ private static boolean isSyntheticAccessPattern(MethodNode mth, InsnNode firstIn
&& retInsn.getArg(0).isSameVar(firstInsn.getResult())
&& firstInsn.getArg(0).isSameVar(mthRegs.get(0));
case SGET:
return mthRegs.size() == 0
return mthRegs.isEmpty()
&& retInsn.getArg(0).isSameVar(firstInsn.getResult());

case IPUT:
Expand All @@ -113,7 +113,7 @@ private static boolean isSyntheticAccessPattern(MethodNode mth, InsnNode firstIn
&& firstInsn.getArg(0).isSameVar(mthRegs.get(0));

case INVOKE:
return mthRegs.size() >= 1
return !mthRegs.isEmpty()
&& firstInsn.getArg(0).isSameVar(mthRegs.get(0))
&& retInsn.getArg(0).isSameVar(firstInsn.getResult());
default:
Expand Down
Loading

0 comments on commit ecb8abb

Please sign in to comment.