From e1dfb4ee59745e6fa2e389fe99625ab96841a099 Mon Sep 17 00:00:00 2001 From: Ahmed Ashour Date: Mon, 29 Apr 2019 15:08:28 +0200 Subject: [PATCH] fix: byte to number without cast (#596) (PR #638) --- .../core/dex/instructions/InvokeNode.java | 1 + .../dex/instructions/args/RegisterArg.java | 2 + .../visitors/typeinference/ITypeBound.java | 6 +++ .../typeinference/TypeBoundConst.java | 13 ++++++ .../typeinference/TypeInferenceVisitor.java | 44 ++++++++++++++++++- ...oleanToInt2.java => TestBooleanToInt.java} | 10 ++--- .../smali/conditions/TestBooleanToInt.smali | 20 +++++++++ .../smali/conditions/TestBooleanToInt2.smali | 20 --------- 8 files changed, 88 insertions(+), 28 deletions(-) rename jadx-core/src/test/java/jadx/tests/integration/conditions/{TestBooleanToInt2.java => TestBooleanToInt.java} (69%) create mode 100644 jadx-core/src/test/smali/conditions/TestBooleanToInt.smali delete mode 100644 jadx-core/src/test/smali/conditions/TestBooleanToInt2.smali diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/InvokeNode.java b/jadx-core/src/main/java/jadx/core/dex/instructions/InvokeNode.java index a2dcb8ded..601ed9c40 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/InvokeNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/InvokeNode.java @@ -46,6 +46,7 @@ public class InvokeNode extends InsnNode implements CallMthInterface { return type; } + @Override public MethodInfo getCallMth() { return mth; } diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/RegisterArg.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/RegisterArg.java index a8ef88e14..3e32332a1 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/RegisterArg.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/RegisterArg.java @@ -81,6 +81,7 @@ public class RegisterArg extends InsnArg implements Named { } } + @Override public String getName() { if (isThis()) { return THIS_ARG_NAME; @@ -91,6 +92,7 @@ public class RegisterArg extends InsnArg implements Named { return sVar.getName(); } + @Override public void setName(String name) { if (sVar != null && name != null) { sVar.setName(name); diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/ITypeBound.java b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/ITypeBound.java index 099ff773c..6d93df77f 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/ITypeBound.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/ITypeBound.java @@ -1,9 +1,15 @@ package jadx.core.dex.visitors.typeinference; +import org.jetbrains.annotations.Nullable; + import jadx.core.dex.instructions.args.ArgType; +import jadx.core.dex.instructions.args.RegisterArg; public interface ITypeBound { BoundEnum getBound(); ArgType getType(); + + @Nullable + RegisterArg getArg(); } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeBoundConst.java b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeBoundConst.java index 344374378..ba21455a4 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeBoundConst.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeBoundConst.java @@ -3,14 +3,22 @@ package jadx.core.dex.visitors.typeinference; import java.util.Objects; import jadx.core.dex.instructions.args.ArgType; +import jadx.core.dex.instructions.args.RegisterArg; public final class TypeBoundConst implements ITypeBound { private final BoundEnum bound; private final ArgType type; + private final RegisterArg arg; + public TypeBoundConst(BoundEnum bound, ArgType type) { + this(bound, type, null); + } + + public TypeBoundConst(BoundEnum bound, ArgType type, RegisterArg arg) { this.bound = bound; this.type = type; + this.arg = arg; } @Override @@ -23,6 +31,11 @@ public final class TypeBoundConst implements ITypeBound { return type; } + @Override + public RegisterArg getArg() { + return arg; + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java index a4dedd557..077ec1435 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java @@ -21,6 +21,7 @@ import jadx.core.dex.instructions.IndexInsnNode; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.PhiInsn; import jadx.core.dex.instructions.args.ArgType; +import jadx.core.dex.instructions.args.CodeVar; import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.LiteralArg; import jadx.core.dex.instructions.args.PrimitiveType; @@ -81,7 +82,11 @@ public final class TypeInferenceVisitor extends AbstractVisitor { resolved = false; } } - if (!resolved) { + if (resolved) { + for (SSAVar var : new ArrayList<>(mth.getSVars())) { + processIncompatiblePrimitives(mth, var); + } + } else { for (SSAVar var : new ArrayList<>(mth.getSVars())) { tryInsertAdditionalInsn(mth, var); } @@ -249,7 +254,7 @@ public final class TypeInferenceVisitor extends AbstractVisitor { if (insn == null) { return null; } - return new TypeBoundConst(BoundEnum.USE, regArg.getInitType()); + return new TypeBoundConst(BoundEnum.USE, regArg.getInitType(), regArg); } private boolean tryPossibleTypes(SSAVar var, ArgType type) { @@ -375,4 +380,39 @@ public final class TypeInferenceVisitor extends AbstractVisitor { } return false; } + + private void processIncompatiblePrimitives(MethodNode mth, SSAVar var) { + if (var.getAssign().getType() == ArgType.BOOLEAN) { + for (ITypeBound bound : var.getTypeInfo().getBounds()) { + if (bound.getBound() == BoundEnum.USE + && bound.getType().isPrimitive() && bound.getType() != ArgType.BOOLEAN) { + InsnNode insn = bound.getArg().getParentInsn(); + if (insn.getType() == InsnType.CAST) { + continue; + }; + + IndexInsnNode castNode = new IndexInsnNode(InsnType.CAST, bound.getType(), 1); + castNode.addArg(bound.getArg()); + castNode.setResult(InsnArg.reg(bound.getArg().getRegNum(), bound.getType())); + + SSAVar newVar = mth.makeNewSVar(castNode.getResult().getRegNum(), castNode.getResult()); + CodeVar codeVar = new CodeVar(); + codeVar.setType(bound.getType()); + newVar.setCodeVar(codeVar); + newVar.getTypeInfo().setType(bound.getType()); + + for (int i = insn.getArgsCount() - 1; i >= 0; i--) { + if (insn.getArg(i) == bound.getArg()) { + insn.setArg(i, castNode.getResult().duplicate()); + break; + } + } + + BlockNode blockNode = BlockUtils.getBlockByInsn(mth, insn); + List insnList = blockNode.getInstructions(); + insnList.add(insnList.indexOf(insn), castNode); + } + } + } + } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToInt2.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToInt.java similarity index 69% rename from jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToInt2.java rename to jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToInt.java index 46927ae66..af8424ff9 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToInt2.java +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToInt.java @@ -5,11 +5,10 @@ import static org.hamcrest.Matchers.containsString; import org.junit.jupiter.api.Test; -import jadx.NotYetImplemented; import jadx.core.dex.nodes.ClassNode; import jadx.tests.api.SmaliTest; -public class TestBooleanToInt2 extends SmaliTest { +public class TestBooleanToInt extends SmaliTest { /** private boolean showConsent; @@ -17,14 +16,13 @@ public class TestBooleanToInt2 extends SmaliTest { public void write(int b) { } - public void writeToParcel(TestBooleanToInt2 testBooleanToInt2) { - testBooleanToInt2.write(this.showConsent ? 1 : 0); + public void writeToParcel(TestBooleanToInt testBooleanToInt) { + testBooleanToInt.write(this.showConsent ? 1 : 0); } */ @Test - @NotYetImplemented public void test() { - ClassNode cls = getClassNodeFromSmaliWithPath("conditions", "TestBooleanToInt2"); + ClassNode cls = getClassNodeFromSmaliWithPath("conditions", "TestBooleanToInt"); String code = cls.getCode().toString(); assertThat(code, containsString("write(this.showConsent ? 1 : 0);")); diff --git a/jadx-core/src/test/smali/conditions/TestBooleanToInt.smali b/jadx-core/src/test/smali/conditions/TestBooleanToInt.smali new file mode 100644 index 000000000..63caa05d2 --- /dev/null +++ b/jadx-core/src/test/smali/conditions/TestBooleanToInt.smali @@ -0,0 +1,20 @@ +.class public LTestBooleanToInt; +.super Ljava/lang/Object; + +.field private showConsent:Z + +.method public writeToParcel(LTestBooleanToInt;)V + .locals 0 + + iget-boolean p1, p0, LTestBooleanToInt;->showConsent:Z + + invoke-virtual {p0, p1}, LTestBooleanToInt;->write(I)V + + return-void +.end method + +.method public write(I)V + .locals 0 + + return-void +.end method diff --git a/jadx-core/src/test/smali/conditions/TestBooleanToInt2.smali b/jadx-core/src/test/smali/conditions/TestBooleanToInt2.smali deleted file mode 100644 index 33d92325a..000000000 --- a/jadx-core/src/test/smali/conditions/TestBooleanToInt2.smali +++ /dev/null @@ -1,20 +0,0 @@ -.class public LTestBooleanToInt2; -.super Ljava/lang/Object; - -.field private showConsent:Z - -.method public writeToParcel(LTestBooleanToInt2;)V - .locals 0 - - iget-boolean p1, p0, LTestBooleanToInt2;->showConsent:Z - - invoke-virtual {p0, p1}, LTestBooleanToInt2;->write(I)V - - return-void -.end method - -.method public write(I)V - .locals 0 - - return-void -.end method