fix: use type from new-instance if differ from constructor call (#2285)

This commit is contained in:
Skylot 2024-09-20 21:34:21 +01:00
parent efa2f5d172
commit 23696d3971
No known key found for this signature in database
GPG Key ID: 47A4975761262B6A
5 changed files with 134 additions and 3 deletions

View File

@ -25,8 +25,12 @@ public final class ConstructorInsn extends BaseInvokeNode {
}
public ConstructorInsn(MethodNode mth, InvokeNode invoke) {
this(mth, invoke, invoke.getCallMth());
}
public ConstructorInsn(MethodNode mth, InvokeNode invoke, MethodInfo callMth) {
super(InsnType.CONSTRUCTOR, invoke.getArgsCount() - 1);
this.callMth = invoke.getCallMth();
this.callMth = callMth;
this.callType = getCallType(mth, callMth.getDeclClass(), invoke.getArg(0));
int argsCount = invoke.getArgsCount();
for (int i = 1; i < argsCount; i++) {

View File

@ -6,9 +6,13 @@ import org.jetbrains.annotations.Nullable;
import jadx.core.codegen.TypeGen;
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.MethodInfo;
import jadx.core.dex.instructions.IndexInsnNode;
import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.InvokeNode;
import jadx.core.dex.instructions.PhiInsn;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.LiteralArg;
import jadx.core.dex.instructions.args.RegisterArg;
@ -59,10 +63,17 @@ public class ConstructorVisitor extends AbstractVisitor {
private static boolean processInvoke(MethodNode mth, BlockNode block, int indexInBlock, InsnRemover remover) {
InvokeNode inv = (InvokeNode) block.getInstructions().get(indexInBlock);
if (!inv.getCallMth().isConstructor()) {
MethodInfo callMth = inv.getCallMth();
if (!callMth.isConstructor()) {
return false;
}
ConstructorInsn co = new ConstructorInsn(mth, inv);
ArgType instType = searchInstanceType(inv);
if (instType != null && !instType.equals(callMth.getDeclClass().getType())) {
ClassInfo instCls = ClassInfo.fromType(mth.root(), instType);
callMth = MethodInfo.fromDetails(mth.root(), instCls, callMth.getName(),
callMth.getArgumentsTypes(), callMth.getReturnType());
}
ConstructorInsn co = new ConstructorInsn(mth, inv, callMth);
if (canRemoveConstructor(mth, co)) {
remover.addAndUnbind(inv);
return false;
@ -101,6 +112,18 @@ public class ConstructorVisitor extends AbstractVisitor {
return true;
}
private static @Nullable ArgType searchInstanceType(InvokeNode inv) {
InsnArg instanceArg = inv.getInstanceArg();
if (instanceArg == null || !instanceArg.isRegister()) {
return null;
}
InsnNode assignInsn = ((RegisterArg) instanceArg).getSVar().getAssignInsn();
if (assignInsn == null || assignInsn.getType() != InsnType.NEW_INSTANCE) {
return null;
}
return ((IndexInsnNode) assignInsn).getIndexAsType();
}
private static RegisterArg insertPhiInsn(MethodNode mth, BlockNode curBlock,
RegisterArg instArg, ConstructorInsn otherCtr) {
BlockNode otherBlock = BlockUtils.getBlockByInsn(mth, otherCtr);

View File

@ -0,0 +1,20 @@
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;
/**
* Constructor called on object instance is from Object not instance type
*/
public class TestConstructor2 extends SmaliTest {
@Test
public void test() {
assertThat(getClassNodeFromSmaliFiles())
.code()
.containsOne("A a = new A();");
}
}

View File

@ -0,0 +1,5 @@
.class public final Lothers/TestConstructor2$A;
.super Ljava/lang/Object;
.field public a:I
.field public b:Ljava/util/ArrayDeque;

View File

@ -0,0 +1,79 @@
.class public Lothers/TestConstructor2;
.super Ljava/lang/Object;
.field public a:Ljava/util/HashMap;
.method public final a(III)V
.registers 6
.line 1
.line 2
new-instance v0, Lothers/TestConstructor2$A;
.line 3
.line 4
.line 5
invoke-direct {v0}, Ljava/lang/Object;-><init>()V
.line 6
.line 7
if-gt p2, p3, :cond_1c
.line 8
.line 9
new-instance p2, Ljava/util/ArrayDeque;
.line 10
.line 11
iget v1, v0, Lothers/TestConstructor2$A;->a:I
.line 12
.line 13
.line 14
invoke-direct {p2, v1}, Ljava/util/ArrayDeque;-><init>(I)V
.line 15
.line 16
iput-object p2, v0, Lothers/TestConstructor2$A;->b:Ljava/util/ArrayDeque;
.line 17
.line 18
iput p3, v0, Lothers/TestConstructor2$A;->a:I
.line 19
.line 20
iget-object p2, p0, Lothers/TestConstructor2;->a:Ljava/util/HashMap;
.line 21
.line 22
.line 23
invoke-static {p1}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
.line 24
move-result-object p1
.line 25
.line 26
.line 27
invoke-virtual {p2, p1, v0}, Ljava/util/HashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
.line 28
return-void
.line 29
.line 30
:cond_1c
new-instance p1, Ljava/lang/IllegalArgumentException;
.line 31
.line 32
const-string/jumbo p2, "error"
.line 33
.line 34
.line 35
invoke-direct {p1, p2}, Ljava/lang/IllegalArgumentException;-><init>(Ljava/lang/String;)V
.line 36
throw p1
.end method