fix: insert new filled array insn before first usage (#2340)

This commit is contained in:
Skylot
2024-11-07 20:02:41 +00:00
parent be6cb573b1
commit f0513a1a55
3 changed files with 71 additions and 4 deletions
@@ -25,7 +25,6 @@ import jadx.core.dex.nodes.IFieldInfoRef;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.visitors.shrink.CodeShrinkVisitor;
import jadx.core.utils.BlockUtils;
import jadx.core.utils.InsnList;
import jadx.core.utils.InsnRemover;
import jadx.core.utils.InsnUtils;
@@ -109,11 +108,15 @@ public class ReplaceNewArray extends AbstractVisitor {
}
// collect put instructions sorted by array index
SortedMap<Long, InsnNode> arrPuts = new TreeMap<>();
InsnNode firstNotAPutUsage = null;
for (RegisterArg registerArg : useList) {
InsnNode parentInsn = registerArg.getParentInsn();
if (parentInsn == null
|| parentInsn.getType() != InsnType.APUT
|| !arrArg.sameRegAndSVar(parentInsn.getArg(0))) {
if (firstNotAPutUsage == null) {
firstNotAPutUsage = parentInsn;
}
continue;
}
Object constVal = InsnUtils.getConstValueByArg(mth.root(), parentInsn.getArg(1));
@@ -158,12 +161,23 @@ public class ReplaceNewArray extends AbstractVisitor {
remover.addAndUnbind(put);
prevIndex = index;
}
// add missing trailing zeros
for (long i = prevIndex + 1; i < len; i++) {
filledArr.addArg(InsnArg.lit(0, elemType));
}
remover.addAndUnbind(newArrayInsn);
// place new insn at last array put or before first usage
InsnNode lastPut = arrPuts.get(arrPuts.lastKey());
int replaceIndex = InsnList.getIndex(instructions, lastPut);
instructions.set(replaceIndex, filledArr);
BlockUtils.replaceInsn(mth, lastPut, filledArr);
int newInsnPos = InsnList.getIndex(instructions, lastPut);
if (firstNotAPutUsage != null) {
int idx = InsnList.getIndex(instructions, firstNotAPutUsage);
if (idx != -1) {
// TODO: check that all args already assigned
newInsnPos = Math.min(idx, newInsnPos);
}
}
instructions.add(newInsnPos, filledArr);
return true;
}
@@ -0,0 +1,17 @@
package jadx.tests.integration.arrays;
import org.junit.jupiter.api.Test;
import jadx.tests.api.SmaliTest;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
public class TestArrayInitField2 extends SmaliTest {
@Test
public void test() {
forceDecompiledCheck();
assertThat(getClassNodeFromSmali())
.code()
.containsOne("static long[] myArr = {1282979400, 0, 0};");
}
}
@@ -0,0 +1,36 @@
.class public Larrays/TestArrayInitField2;
.super Ljava/lang/Object;
.field static myArr:[J
.method static constructor <clinit>()V
.locals 4
const v0, 0x3
new-array v0, v0, [J
sput-object v0, Larrays/TestArrayInitField2;->myArr:[J
const/4 v1, 0x0
const-wide/32 v2, 0x4c78b648
aput-wide v2, v0, v1
return-void
nop
.end method
.method public check()V
.registers 5
sget-object v0, Larrays/TestArrayInitField2;->myArr:[J
invoke-static {v0}, Lorg/assertj/core/api/Assertions;->assertThat([J)Lorg/assertj/core/api/AbstractLongArrayAssert;
move-result-object v0
const/4 v1, 0x3
invoke-virtual {v0, v1}, Lorg/assertj/core/api/AbstractLongArrayAssert;->hasSize(I)Lorg/assertj/core/api/AbstractLongArrayAssert;
sget-object v0, Larrays/TestArrayInitField2;->myArr:[J
const/4 v1, 0x0
aget-wide v0, v0, v1
invoke-static {v0, v1}, Lorg/assertj/core/api/Assertions;->assertThat(J)Lorg/assertj/core/api/AbstractLongAssert;
move-result-object v0
const-wide/32 v2, 0x4c78b648
invoke-virtual {v0, v2, v3}, Lorg/assertj/core/api/AbstractLongAssert;->isEqualTo(J)Lorg/assertj/core/api/AbstractLongAssert;
return-void
.end method