fix: handle quick return on branched constructor (#2240)

This commit is contained in:
Skylot
2024-08-09 22:54:13 +01:00
parent e9d770ae9e
commit 280f3870a9
4 changed files with 131 additions and 4 deletions
@@ -1,5 +1,7 @@
package jadx.core.dex.visitors;
import java.util.List;
import org.jetbrains.annotations.Nullable;
import jadx.core.codegen.TypeGen;
@@ -107,7 +109,20 @@ public class ConstructorVisitor extends AbstractVisitor {
}
BlockNode crossBlock = BlockUtils.getPathCross(mth, curBlock, otherBlock);
if (crossBlock == null) {
throw new JadxRuntimeException("Path cross not found for blocks: " + curBlock + " and " + otherBlock);
// no path cross => PHI insn not needed
// use new SSA var on usage from current path
RegisterArg newResArg = instArg.duplicateWithNewSSAVar(mth);
List<BlockNode> pathBlocks = BlockUtils.collectAllSuccessors(mth, curBlock, true);
for (RegisterArg useReg : instArg.getSVar().getUseList()) {
InsnNode parentInsn = useReg.getParentInsn();
if (parentInsn != null) {
BlockNode useBlock = BlockUtils.getBlockByInsn(mth, parentInsn, pathBlocks);
if (useBlock != null) {
parentInsn.replaceArg(useReg, newResArg.duplicate());
}
}
}
return newResArg;
}
RegisterArg newResArg = instArg.duplicateWithNewSSAVar(mth);
RegisterArg useArg = otherCtr.getResult();
@@ -249,8 +249,11 @@ public class BlockUtils {
|| type == InsnType.CONTINUE;
}
@Nullable
public static BlockNode getBlockByInsn(MethodNode mth, @Nullable InsnNode insn) {
public static @Nullable BlockNode getBlockByInsn(MethodNode mth, @Nullable InsnNode insn) {
return getBlockByInsn(mth, insn, mth.getBasicBlocks());
}
public static @Nullable BlockNode getBlockByInsn(MethodNode mth, @Nullable InsnNode insn, List<BlockNode> blocks) {
if (insn == null) {
return null;
}
@@ -260,7 +263,7 @@ public class BlockUtils {
if (insn.contains(AFlag.WRAPPED)) {
return getBlockByWrappedInsn(mth, insn);
}
for (BlockNode bn : mth.getBasicBlocks()) {
for (BlockNode bn : blocks) {
if (blockContains(bn, insn)) {
return bn;
}
@@ -0,0 +1,18 @@
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 TestConstructorBranched3 extends SmaliTest {
@Test
public void test() {
disableCompilation();
assertThat(getClassNodeFromSmali())
.code()
.countString(4, "return new f(");
}
}
@@ -0,0 +1,91 @@
.class public Lothers/TestConstructorBranched3;
.super Ljava/lang/Object;
.method public static final test(Ljava/lang/Class;)Lml/f;
.registers 5
const/4 v0, 0x0
:goto_1
invoke-virtual {p0}, Ljava/lang/Class;->isArray()Z
move-result v1
if-eqz v1, :cond_13
add-int/lit8 v0, v0, 0x1
invoke-virtual {p0}, Ljava/lang/Class;->getComponentType()Ljava/lang/Class;
move-result-object p0
const-string v1, "currentClass.componentType"
invoke-static {p0, v1}, Lve/e;->l(Ljava/lang/Object;Ljava/lang/String;)V
goto :goto_1
:cond_13
invoke-virtual {p0}, Ljava/lang/Class;->isPrimitive()Z
move-result v1
if-eqz v1, :cond_68
sget-object v1, Ljava/lang/Void;->TYPE:Ljava/lang/Class;
invoke-static {p0, v1}, Lve/e;->g(Ljava/lang/Object;Ljava/lang/Object;)Z
move-result v1
if-eqz v1, :cond_31
new-instance p0, Lml/f;
sget-object v1, Lgk/k$a;->e:Lhl/c;
invoke-virtual {v1}, Lhl/c;->i()Lhl/b;
move-result-object v1
invoke-static {v1}, Lhl/a;->l(Lhl/b;)Lhl/a;
move-result-object v1
invoke-direct {p0, v1, v0}, Lml/f;-><init>(Lhl/a;I)V
return-object p0
:cond_31
invoke-virtual {p0}, Ljava/lang/Class;->getName()Ljava/lang/String;
move-result-object p0
invoke-static {p0}, Lpl/b;->c(Ljava/lang/String;)Lpl/b;
move-result-object p0
invoke-virtual {p0}, Lpl/b;->r()Lgk/i;
move-result-object p0
const-string v1, "get(currentClass.name).primitiveType"
invoke-static {p0, v1}, Lve/e;->l(Ljava/lang/Object;Ljava/lang/String;)V
new-instance v1, Lml/f;
if-lez v0, :cond_58
.line 1
iget-object p0, p0, Lgk/i;->d:Ljj/d;
invoke-interface {p0}, Ljj/d;->getValue()Ljava/lang/Object;
move-result-object p0
check-cast p0, Lhl/b;
.line 2
invoke-static {p0}, Lhl/a;->l(Lhl/b;)Lhl/a;
move-result-object p0
add-int/lit8 v0, v0, -0x1
invoke-direct {v1, p0, v0}, Lml/f;-><init>(Lhl/a;I)V
return-object v1
.line 3
:cond_58
iget-object p0, p0, Lgk/i;->c:Ljj/d;
invoke-interface {p0}, Ljj/d;->getValue()Ljava/lang/Object;
move-result-object p0
check-cast p0, Lhl/b;
.line 4
invoke-static {p0}, Lhl/a;->l(Lhl/b;)Lhl/a;
move-result-object p0
invoke-direct {v1, p0, v0}, Lml/f;-><init>(Lhl/a;I)V
return-object v1
:cond_68
invoke-static {p0}, Lpk/b;->b(Ljava/lang/Class;)Lhl/a;
move-result-object p0
sget-object v1, Lik/c;->a:Lik/c;
invoke-virtual {p0}, Lhl/a;->b()Lhl/b;
move-result-object v2
const-string v3, "javaClassId.asSingleFqName()"
invoke-static {v2, v3}, Lve/e;->l(Ljava/lang/Object;Ljava/lang/String;)V
invoke-virtual {v1, v2}, Lik/c;->f(Lhl/b;)Lhl/a;
move-result-object v1
if-nez v1, :cond_7e
goto :goto_7f
:cond_7e
move-object p0, v1
:goto_7f
new-instance v1, Lml/f;
invoke-direct {v1, p0, v0}, Lml/f;-><init>(Lhl/a;I)V
return-object v1
.end method