From ed9fe8a57321d49d3fbe1bb5fde4c799ee859ca6 Mon Sep 17 00:00:00 2001 From: Skylot Date: Sat, 13 Jul 2019 13:10:23 +0300 Subject: [PATCH] fix: incorrect init values of inherited fields --- .../core/dex/visitors/ExtractFieldInit.java | 21 ++++++- .../integration/others/TestFieldInit3.java | 57 +++++++++++++++++++ 2 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 jadx-core/src/test/java/jadx/tests/integration/others/TestFieldInit3.java diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ExtractFieldInit.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ExtractFieldInit.java index bf4f71100e1..1356cfb9e1f 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ExtractFieldInit.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ExtractFieldInit.java @@ -92,7 +92,7 @@ private static void moveStaticFieldsInit(ClassNode cls) { List initInsns = getFieldAssigns(classInitMth, field, InsnType.SPUT); if (initInsns.size() == 1) { InsnNode insn = initInsns.get(0); - if (checkInsn(insn)) { + if (checkInsn(cls, insn)) { InsnArg arg = insn.getArg(0); if (arg instanceof InsnWrapArg) { ((InsnWrapArg) arg).getWrapInsn().add(AFlag.DECLARE_VAR); @@ -137,7 +137,7 @@ private static void moveCommonFieldsInit(ClassNode cls) { // TODO: check not only first block BlockNode blockNode = constrMth.getBasicBlocks().get(0); for (InsnNode insn : blockNode.getInstructions()) { - if (insn.getType() == InsnType.IPUT && checkInsn(insn)) { + if (insn.getType() == InsnType.IPUT && checkInsn(cls, insn)) { info.getPutInsns().add(insn); } else if (!info.getPutInsns().isEmpty()) { break; @@ -199,7 +199,22 @@ private static boolean compareInsns(List base, List other) { return true; } - private static boolean checkInsn(InsnNode insn) { + private static boolean checkInsn(ClassNode cls, InsnNode insn) { + if (insn instanceof IndexInsnNode) { + FieldInfo fieldInfo = (FieldInfo) ((IndexInsnNode) insn).getIndex(); + if (!fieldInfo.getDeclClass().equals(cls.getClassInfo())) { + // exclude fields from super classes + return false; + } + FieldNode fieldNode = cls.dex().resolveField(fieldInfo); + if (fieldNode == null) { + // exclude inherited fields (not declared in this class) + return false; + } + } else { + return false; + } + InsnArg arg = insn.getArg(0); if (arg.isInsnWrap()) { InsnNode wrapInsn = ((InsnWrapArg) arg).getWrapInsn(); diff --git a/jadx-core/src/test/java/jadx/tests/integration/others/TestFieldInit3.java b/jadx-core/src/test/java/jadx/tests/integration/others/TestFieldInit3.java new file mode 100644 index 00000000000..bbb58a20fc2 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/others/TestFieldInit3.java @@ -0,0 +1,57 @@ +package jadx.tests.integration.others; + +import org.junit.jupiter.api.Test; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.IntegrationTest; + +import static jadx.tests.api.utils.JadxMatchers.containsOne; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +public class TestFieldInit3 extends IntegrationTest { + + public static class TestCls { + + public abstract static class A { + public int field = 4; + } + + public static final class B extends A { + public B() { + // IPUT for A.field + super.field = 7; + } + } + + public static final class C extends A { + public int other = 11; + + public C() { + // IPUT for C.field not A.field !!! + this.field = 9; + } + } + + public static final class D extends A { + } + + public void check() { + assertThat(new B().field, is(7)); + assertThat(new C().field, is(9)); + assertThat(new C().other, is(11)); + assertThat(new D().field, is(4)); + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, containsOne("public int field = 4;")); + assertThat(code, containsOne("field = 7;")); + assertThat(code, containsOne("field = 9;")); + assertThat(code, containsOne("public int other = 11;")); + } +}