diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ConstructorVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ConstructorVisitor.java index e7a7a2bf7..fe866cc0c 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ConstructorVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ConstructorVisitor.java @@ -2,6 +2,8 @@ package jadx.core.dex.visitors; import java.util.ArrayList; +import org.jetbrains.annotations.Nullable; + import jadx.core.codegen.TypeGen; import jadx.core.dex.info.MethodInfo; import jadx.core.dex.instructions.InsnType; @@ -105,8 +107,12 @@ public class ConstructorVisitor extends AbstractVisitor { } /** - * Replace call of synthetic constructor + * Replace call of synthetic constructor with all 'null' args + * to a non-synthetic or default constructor if possible. + * + * @return insn for replacement or null if replace not needed or not possible. */ + @Nullable private static ConstructorInsn processConstructor(MethodNode mth, ConstructorInsn co) { MethodNode callMth = mth.dex().resolveMethod(co.getCallMth()); if (callMth == null @@ -125,11 +131,11 @@ public class ConstructorVisitor extends AbstractVisitor { boolean passThis = instanceArg.isThis(); String ctrId = "(" + (passThis ? TypeGen.signature(instanceArg.getInitType()) : "") + ")V"; MethodNode defCtr = classNode.searchMethodByShortId(ctrId); - if (defCtr == null) { + if (defCtr == null || defCtr.equals(callMth) || defCtr.getAccessFlags().isSynthetic()) { return null; } ConstructorInsn newInsn = new ConstructorInsn(defCtr.getMethodInfo(), co.getCallType()); - newInsn.setResult(co.getResult()); + newInsn.setResult(co.getResult().duplicate()); return newInsn; } diff --git a/jadx-core/src/test/java/jadx/tests/integration/others/TestSyntheticConstructor.java b/jadx-core/src/test/java/jadx/tests/integration/others/TestSyntheticConstructor.java new file mode 100644 index 000000000..b981c67c0 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/others/TestSyntheticConstructor.java @@ -0,0 +1,27 @@ +package jadx.tests.integration.others; + +import org.junit.jupiter.api.Test; + +import jadx.tests.api.SmaliTest; + +import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; + +public class TestSyntheticConstructor extends SmaliTest { + // @formatter:off + /* + public class Test { + static { + new BuggyConstructor(); + } + } + */ + // @formatter:on + + @Test + public void test() { + disableCompilation(); + assertThat(getClassNodeFromSmaliFiles("Test")) + .code() + .containsLine(2, "new BuggyConstructor();"); + } +} diff --git a/jadx-core/src/test/smali/others/TestSyntheticConstructor/BuggyConstructor.smali b/jadx-core/src/test/smali/others/TestSyntheticConstructor/BuggyConstructor.smali new file mode 100644 index 000000000..44402ef71 --- /dev/null +++ b/jadx-core/src/test/smali/others/TestSyntheticConstructor/BuggyConstructor.smali @@ -0,0 +1,11 @@ +.class public LBuggyConstructor; +.super Ljava/lang/Object; +.source "BuggyConstructor.java" + +#.implements LInterfaceClass; + +.method public synthetic constructor ()V + .locals 0 + invoke-direct {p0}, Ljava/lang/Object;->()V + return-void +.end method diff --git a/jadx-core/src/test/smali/others/TestSyntheticConstructor/Test.smali b/jadx-core/src/test/smali/others/TestSyntheticConstructor/Test.smali new file mode 100644 index 000000000..bbc5e261c --- /dev/null +++ b/jadx-core/src/test/smali/others/TestSyntheticConstructor/Test.smali @@ -0,0 +1,11 @@ +.class public Lothers/Test; +.super Ljava/lang/Object; +.source "Test.java" + +.field public static final A00:Ljava/lang/Object; + +.method public static constructor ()V + .locals 1 + new-instance v0, LBuggyConstructor; + invoke-direct {v0}, LBuggyConstructor;->()V +.end method