From 7bd175220ea30619e5c7151a9ff71b4f641094b4 Mon Sep 17 00:00:00 2001 From: Skylot Date: Tue, 26 Feb 2019 19:09:13 +0300 Subject: [PATCH] fix: add correct type propagation for check-cast and move instructions (#401) --- .../visitors/typeinference/TypeUpdate.java | 35 ++++++++----- .../integration/types/TestTypeResolver7.java | 49 +++++++++++++++++++ 2 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 jadx-core/src/test/java/jadx/tests/integration/types/TestTypeResolver7.java 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 9362dee52..591a64c71 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 @@ -252,6 +252,7 @@ public final class TypeUpdate { registry.put(InsnType.ARITH, this::suggestAllSameListener); registry.put(InsnType.NEG, this::suggestAllSameListener); registry.put(InsnType.NOT, this::suggestAllSameListener); + registry.put(InsnType.CHECK_CAST, this::checkCastListener); return registry; } @@ -263,20 +264,23 @@ public final class TypeUpdate { private TypeUpdateResult moveListener(TypeUpdateInfo updateInfo, InsnNode insn, InsnArg arg, ArgType candidateType) { boolean assignChanged = isAssign(insn, arg); InsnArg changeArg = assignChanged ? insn.getArg(0) : insn.getResult(); - TypeUpdateResult result = updateTypeChecked(updateInfo, changeArg, candidateType); - if (result == REJECT && changeArg.getType().isTypeKnown()) { + boolean allowReject; + if (changeArg.getType().isTypeKnown()) { // allow result to be wider - if (assignChanged) { - TypeCompareEnum compareTypes = comparator.compareTypes(candidateType, changeArg.getType()); - if (compareTypes.isWider() && inBounds(changeArg, candidateType)) { - return CHANGED; - } + TypeCompareEnum compareTypes = comparator.compareTypes(candidateType, changeArg.getType()); + boolean correctType = assignChanged ? compareTypes.isWider() : compareTypes.isNarrow(); + if (correctType && inBounds(changeArg, candidateType)) { + allowReject = true; } else { - TypeCompareEnum compareTypes = comparator.compareTypes(changeArg.getType(), candidateType); - if (compareTypes.isWider() && inBounds(changeArg, candidateType)) { - return CHANGED; - } + return REJECT; } + } else { + allowReject = false; + } + + TypeUpdateResult result = updateTypeChecked(updateInfo, changeArg, candidateType); + if (result == REJECT && allowReject) { + return CHANGED; } return result; } @@ -324,6 +328,15 @@ public final class TypeUpdate { return allSame ? SAME : CHANGED; } + private TypeUpdateResult checkCastListener(TypeUpdateInfo updateInfo, InsnNode insn, InsnArg arg, ArgType candidateType) { + if (!isAssign(insn, arg)) { + return SAME; + } + InsnArg insnArg = insn.getArg(0); + TypeUpdateResult result = updateTypeChecked(updateInfo, insnArg, candidateType); + return result == REJECT ? SAME : result; + } + private TypeUpdateResult arrayGetListener(TypeUpdateInfo updateInfo, InsnNode insn, InsnArg arg, ArgType candidateType) { if (isAssign(insn, arg)) { return updateTypeChecked(updateInfo, insn.getArg(0), ArgType.array(candidateType)); diff --git a/jadx-core/src/test/java/jadx/tests/integration/types/TestTypeResolver7.java b/jadx-core/src/test/java/jadx/tests/integration/types/TestTypeResolver7.java new file mode 100644 index 000000000..c4f1b0e7a --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/types/TestTypeResolver7.java @@ -0,0 +1,49 @@ +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.junit.Assert.assertThat; + +public class TestTypeResolver7 extends IntegrationTest { + + public static class TestCls { + public void test(boolean a, boolean b) { + Object obj = null; + if (a) { + use(b ? (Exception) getObj() : (Exception) obj); + } else { + Runnable r = (Runnable) obj; + if (b) { + r = (Runnable) getObj(); + } + use(r); + } + } + + private Object getObj() { + return null; + } + + private void use(Exception e) {} + + private void use(Runnable r) {} + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, containsOne("use(b ? (Exception) getObj() : null);")); + } + + @Test + public void testNoDebug() { + noDebugInfo(); + getClassNode(TestCls.class); + } +}