fix: use correct approach to get prev block on path (#2239)

This commit is contained in:
Skylot
2024-08-09 22:03:44 +01:00
parent 5f1bd1d9ba
commit e9d770ae9e
5 changed files with 175 additions and 25 deletions
@@ -115,8 +115,8 @@ public class ConstructorVisitor extends AbstractVisitor {
PhiInsn phiInsn = SSATransform.addPhi(mth, crossBlock, useArg.getRegNum());
phiInsn.setResult(useArg.duplicate());
phiInsn.bindArg(newResArg.duplicate(), BlockUtils.getPrevBlockOnPath(crossBlock, curBlock));
phiInsn.bindArg(otherResArg.duplicate(), BlockUtils.getPrevBlockOnPath(crossBlock, otherBlock));
phiInsn.bindArg(newResArg.duplicate(), BlockUtils.getPrevBlockOnPath(mth, crossBlock, curBlock));
phiInsn.bindArg(otherResArg.duplicate(), BlockUtils.getPrevBlockOnPath(mth, crossBlock, otherBlock));
phiInsn.rebindArgs();
otherCtr.setResult(otherResArg.duplicate());
@@ -37,6 +37,7 @@ import jadx.core.dex.regions.conditions.IfCondition;
import jadx.core.dex.trycatch.CatchAttr;
import jadx.core.dex.trycatch.ExceptionHandler;
import jadx.core.utils.blocks.BlockSet;
import jadx.core.utils.blocks.DFSIteration;
import jadx.core.utils.exceptions.JadxRuntimeException;
public class BlockUtils {
@@ -437,18 +438,21 @@ public class BlockUtils {
/**
* Return predecessor on path from 'pathStart' block
*/
public static @Nullable BlockNode getPrevBlockOnPath(BlockNode block, BlockNode pathStart) {
List<BlockNode> preds = block.getPredecessors();
if (preds.contains(pathStart)) {
public static @Nullable BlockNode getPrevBlockOnPath(MethodNode mth, BlockNode block, BlockNode pathStart) {
BlockSet preds = BlockSet.from(mth, block.getPredecessors());
if (preds.get(pathStart)) {
return pathStart;
}
Set<BlockNode> path = getAllPathsBlocks(pathStart, block);
for (BlockNode p : preds) {
if (path.contains(p)) {
return p;
DFSIteration dfs = new DFSIteration(mth, pathStart, BlockNode::getCleanSuccessors);
while (true) {
BlockNode next = dfs.next();
if (next == null) {
return null;
}
if (preds.get(next)) {
return next;
}
}
return null;
}
/**
@@ -515,24 +519,13 @@ public class BlockUtils {
private static void visitDFS(MethodNode mth, BlockNode startBlock,
Function<BlockNode, List<BlockNode>> nextFunc, Consumer<BlockNode> visitor) {
BlockSet visited = new BlockSet(mth);
Deque<BlockNode> queue = new ArrayDeque<>();
queue.addLast(startBlock);
visited.set(startBlock);
DFSIteration dfsIteration = new DFSIteration(mth, startBlock, nextFunc);
while (true) {
BlockNode current = queue.pollLast();
if (current == null) {
BlockNode next = dfsIteration.next();
if (next == null) {
return;
}
visitor.accept(current);
List<BlockNode> nextBlocks = nextFunc.apply(current);
int count = nextBlocks.size();
for (int i = count - 1; i >= 0; i--) { // to preserve order in queue
BlockNode next = nextBlocks.get(i);
if (!visited.checkAndSet(next)) {
queue.addLast(next);
}
}
visitor.accept(next);
}
}
@@ -0,0 +1,41 @@
package jadx.core.utils.blocks;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.MethodNode;
public class DFSIteration {
private final Function<BlockNode, List<BlockNode>> nextFunc;
private final Deque<BlockNode> queue;
private final BlockSet visited;
public DFSIteration(MethodNode mth, BlockNode startBlock, Function<BlockNode, List<BlockNode>> next) {
nextFunc = next;
queue = new ArrayDeque<>();
visited = new BlockSet(mth);
queue.addLast(startBlock);
visited.set(startBlock);
}
public @Nullable BlockNode next() {
BlockNode current = queue.pollLast();
if (current == null) {
return null;
}
List<BlockNode> nextBlocks = nextFunc.apply(current);
int count = nextBlocks.size();
for (int i = count - 1; i >= 0; i--) { // to preserve order in queue
BlockNode next = nextBlocks.get(i);
if (!visited.checkAndSet(next)) {
queue.addLast(next);
}
}
return current;
}
}
@@ -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 TestConstructorBranched2 extends SmaliTest {
@Test
public void test() {
disableCompilation();
assertThat(getClassNodeFromSmali())
.code()
.countString(3, "new StringBuilder()");
}
}
@@ -0,0 +1,98 @@
.class public Lothers/TestConstructorBranched2;
.super Ljava/lang/Object;
.method private test(Ljava/util/List;)Ljava/lang/String;
.locals 12
iget-boolean v1, p0, Landroidx/gridlayout/widget/GridLayout$Axis;->horizontal:Z
const/4 v2, 0x1
if-eqz v1, :cond_0
const-string/jumbo v1, "x"
goto :goto_0
:cond_0
const-string/jumbo v1, "y"
:goto_0
new-instance v3, Ljava/lang/StringBuilder;
invoke-direct {v3}, Ljava/lang/StringBuilder;-><init>()V
const/4 v4, 0x1
invoke-interface {p1}, Ljava/util/List;->iterator()Ljava/util/Iterator;
move-result-object v5
const/16 v6, 0x98
:goto_1
invoke-interface {v5}, Ljava/util/Iterator;->hasNext()Z
move-result v6
if-eqz v6, :cond_3
invoke-interface {v5}, Ljava/util/Iterator;->next()Ljava/lang/Object;
move-result-object v6
check-cast v6, Landroidx/gridlayout/widget/GridLayout$Arc;
if-eqz v4, :cond_1
const/4 v4, 0x0
goto :goto_2
:cond_1
const-string v7, ", "
invoke-virtual {v3, v7}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v3
:goto_2
iget-object v7, v6, Landroidx/gridlayout/widget/GridLayout$Arc;->span:Landroidx/gridlayout/widget/GridLayout$Interval;
iget v7, v7, Landroidx/gridlayout/widget/GridLayout$Interval;->min:I
iget-object v8, v6, Landroidx/gridlayout/widget/GridLayout$Arc;->span:Landroidx/gridlayout/widget/GridLayout$Interval;
iget v8, v8, Landroidx/gridlayout/widget/GridLayout$Interval;->max:I
iget-object v9, v6, Landroidx/gridlayout/widget/GridLayout$Arc;->value:Landroidx/gridlayout/widget/GridLayout$MutableInt;
iget v9, v9, Landroidx/gridlayout/widget/GridLayout$MutableInt;->value:I
const-string v10, "-"
new-instance v11, Ljava/lang/StringBuilder;
if-ge v7, v8, :cond_2
invoke-direct {v11}, Ljava/lang/StringBuilder;-><init>()V
invoke-virtual {v11, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v11
invoke-virtual {v11, v8}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
move-result-object v11
invoke-virtual {v11, v10}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v10
invoke-virtual {v10, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v10
invoke-virtual {v10, v7}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
move-result-object v10
const-string v11, ">="
invoke-virtual {v10, v11}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v10
invoke-virtual {v10, v9}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
move-result-object v10
invoke-virtual {v10}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v10
goto :goto_3
:cond_2
invoke-direct {v11}, Ljava/lang/StringBuilder;-><init>()V
invoke-virtual {v11, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v11
invoke-virtual {v11, v7}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
move-result-object v11
invoke-virtual {v11, v10}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v10
invoke-virtual {v10, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v10
invoke-virtual {v10, v8}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
move-result-object v10
const-string v11, "<="
invoke-virtual {v10, v11}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v10
neg-int v11, v9
invoke-virtual {v10, v11}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
move-result-object v10
invoke-virtual {v10}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v10
:goto_3
invoke-virtual {v3, v10}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
goto/16 :goto_1
:cond_3
invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v5
return-object v5
.end method