From 37071dbaf3d39723930552e6eba861e14e917e2a Mon Sep 17 00:00:00 2001 From: Skylot Date: Wed, 5 Dec 2018 22:48:20 +0300 Subject: [PATCH] fix: use soft checks for objects and arrays in 'if' type listener (#401) --- .../core/dex/instructions/args/ArgType.java | 8 +++ .../visitors/typeinference/TypeUpdate.java | 13 +++- .../types/TestConstTypeInference.java | 64 +++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 jadx-core/src/test/java/jadx/tests/integration/types/TestConstTypeInference.java diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java index 5e3de592f..8e9663323 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java @@ -518,6 +518,14 @@ public abstract class ArgType { return false; } + public boolean canBeObject() { + return isObject() || (!isTypeKnown() && contains(PrimitiveType.OBJECT)); + } + + public boolean canBeArray() { + return isArray() || (!isTypeKnown() && contains(PrimitiveType.ARRAY)); + } + public static ArgType convertFromPrimitiveType(PrimitiveType primitiveType) { switch (primitiveType) { case BOOLEAN: diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeUpdate.java b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeUpdate.java index f7e8f974c..0af2cac9f 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeUpdate.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeUpdate.java @@ -306,7 +306,18 @@ public final class TypeUpdate { InsnArg firstArg = insn.getArg(0); InsnArg secondArg = insn.getArg(1); InsnArg updateArg = firstArg == arg ? secondArg : firstArg; - return updateTypeChecked(updateInfo, updateArg, candidateType); + TypeUpdateResult result = updateTypeChecked(updateInfo, updateArg, candidateType); + if (result == REJECT) { + // soft checks for objects and array - exact type not compared + ArgType updateArgType = updateArg.getType(); + if (candidateType.isObject() && updateArgType.canBeObject()) { + return SAME; + } + if (candidateType.isArray() && updateArgType.canBeArray()) { + return SAME; + } + } + return result; } private static boolean isAssign(InsnNode insn, InsnArg arg) { diff --git a/jadx-core/src/test/java/jadx/tests/integration/types/TestConstTypeInference.java b/jadx-core/src/test/java/jadx/tests/integration/types/TestConstTypeInference.java new file mode 100644 index 000000000..8f0afe479 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/types/TestConstTypeInference.java @@ -0,0 +1,64 @@ +package jadx.tests.integration.types; + +import org.junit.Test; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.IntegrationTest; + +import static jadx.tests.api.utils.JadxMatchers.containsOne; +import static org.hamcrest.Matchers.anyOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThat; + +public class TestConstTypeInference extends IntegrationTest { + + public static class TestCls { + private final int a; + + public TestCls() { + this(0); + } + + public TestCls(int a) { + this.a = a; + } + + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null) { + if (getClass() == obj.getClass()) { + TestCls other = (TestCls) obj; + return this.a == other.a; + } + } + return false; + } + + public void check() { + TestCls seven = new TestCls(7); + assertEquals(seven, seven); + assertNotEquals(seven, null); + + TestCls six = new TestCls(6); + assertNotEquals(seven, six); + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, containsOne("obj == this")); + assertThat(code, anyOf(containsOne("obj == null"), containsOne("obj != null"))); + } + + @Test + public void test2() { + noDebugInfo(); + getClassNode(TestCls.class); + } +}