From 2383c401056f956e8af552f5f7a93d1afa8cce88 Mon Sep 17 00:00:00 2001 From: Skylot Date: Wed, 15 May 2019 19:00:13 +0300 Subject: [PATCH] fix: correct arg replace in PHI instruction (#462) --- .../jadx/core/dex/instructions/PhiInsn.java | 72 ++++++++++++------- .../java/jadx/core/dex/nodes/InsnNode.java | 22 ++++-- .../typeinference/TypeInferenceVisitor.java | 9 +-- .../main/java/jadx/core/utils/DebugUtils.java | 3 - 4 files changed, 69 insertions(+), 37 deletions(-) diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/PhiInsn.java b/jadx-core/src/main/java/jadx/core/dex/instructions/PhiInsn.java index 9719b2fb..e66398e4 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/PhiInsn.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/PhiInsn.java @@ -1,9 +1,10 @@ package jadx.core.dex.instructions; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import jadx.core.dex.attributes.AFlag; import jadx.core.dex.instructions.args.ArgType; @@ -17,11 +18,12 @@ import jadx.core.utils.exceptions.JadxRuntimeException; public final class PhiInsn extends InsnNode { - private final Map blockBinds; + // map arguments to blocks (in same order as in arguments list) + private final List blockBinds; public PhiInsn(int regNum, int predecessors) { super(InsnType.PHI, predecessors); - this.blockBinds = new LinkedHashMap<>(predecessors); + this.blockBinds = new ArrayList<>(predecessors); setResult(InsnArg.reg(regNum, ArgType.UNKNOWN)); add(AFlag.DONT_INLINE); add(AFlag.DONT_GENERATE); @@ -34,19 +36,24 @@ public final class PhiInsn extends InsnNode { } public void bindArg(RegisterArg arg, BlockNode pred) { - if (blockBinds.containsValue(pred)) { + if (blockBinds.contains(pred)) { throw new JadxRuntimeException("Duplicate predecessors in PHI insn: " + pred + ", " + this); } - addArg(arg); - blockBinds.put(arg, pred); + super.addArg(arg); + blockBinds.add(pred); } + @Nullable public BlockNode getBlockByArg(RegisterArg arg) { - return blockBinds.get(arg); + int index = getArgIndex(arg); + if (index == -1) { + return null; + } + return blockBinds.get(index); } - public Map getBlockBinds() { - return blockBinds; + public BlockNode getBlockByArgIndex(int argIndex) { + return blockBinds.get(argIndex); } @Override @@ -57,17 +64,20 @@ public final class PhiInsn extends InsnNode { @Override public boolean removeArg(InsnArg arg) { - if (!(arg instanceof RegisterArg)) { + int index = getArgIndex(arg); + if (index == -1) { return false; } - RegisterArg reg = (RegisterArg) arg; - if (super.removeArg(reg)) { - blockBinds.remove(reg); - reg.getSVar().removeUse(reg); - InsnRemover.fixUsedInPhiFlag(reg); - return true; - } - return false; + removeArg(index); + return true; + } + + @Override + protected RegisterArg removeArg(int index) { + RegisterArg reg = (RegisterArg) super.removeArg(index); + blockBinds.remove(index); + InsnRemover.fixUsedInPhiFlag(reg); + return reg; } @Override @@ -75,21 +85,31 @@ public final class PhiInsn extends InsnNode { if (!(from instanceof RegisterArg) || !(to instanceof RegisterArg)) { return false; } - BlockNode pred = getBlockByArg((RegisterArg) from); + + int argIndex = getArgIndex(from); + if (argIndex == -1) { + return false; + } + BlockNode pred = getBlockByArgIndex(argIndex); if (pred == null) { throw new JadxRuntimeException("Unknown predecessor block by arg " + from + " in PHI: " + this); } - if (removeArg(from)) { - RegisterArg reg = (RegisterArg) to; - bindArg(reg, pred); - reg.getSVar().setUsedInPhi(this); - } + removeArg(argIndex); + + RegisterArg reg = (RegisterArg) to; + bindArg(reg, pred); + reg.getSVar().setUsedInPhi(this); return true; } + @Override + public void addArg(InsnArg arg) { + throw new JadxRuntimeException("Direct addArg is forbidden for PHI insn, bindArg must be used"); + } + @Override public void setArg(int n, InsnArg arg) { - throw new JadxRuntimeException("Unsupported operation for PHI node"); + throw new JadxRuntimeException("Direct setArg is forbidden for PHI insn, bindArg must be used"); } @Override diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java index 1a8ee51c..7ee148d3 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java @@ -139,15 +139,29 @@ public class InsnNode extends LineAttrNode { } protected boolean removeArg(InsnArg arg) { + int index = getArgIndex(arg); + if (index == -1) { + return false; + } + removeArg(index); + return true; + } + + protected InsnArg removeArg(int index) { + InsnArg arg = arguments.get(index); + arguments.remove(index); + InsnRemover.unbindArgUsage(null, arg); + return arg; + } + + protected int getArgIndex(InsnArg arg) { int count = getArgsCount(); for (int i = 0; i < count; i++) { if (arg == arguments.get(i)) { - arguments.remove(i); - InsnRemover.unbindArgUsage(null, arg); - return true; + return i; } } - return false; + return -1; } protected void addReg(DecodedInstruction insn, int i, ArgType type) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java index 3e8bbb6e..868b8665 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInferenceVisitor.java @@ -3,7 +3,6 @@ package jadx.core.dex.visitors.typeinference; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -318,10 +317,12 @@ public final class TypeInferenceVisitor extends AbstractVisitor { return false; } } - for (Map.Entry entry : phiInsn.getBlockBinds().entrySet()) { - RegisterArg reg = entry.getKey(); + + int argsCount = phiInsn.getArgsCount(); + for (int argIndex = 0; argIndex < argsCount; argIndex++) { + RegisterArg reg = phiInsn.getArg(argIndex); if (reg.getSVar() == var) { - BlockNode blockNode = entry.getValue(); + BlockNode blockNode = phiInsn.getBlockByArgIndex(argIndex); InsnNode lastInsn = BlockUtils.getLastInsn(blockNode); if (lastInsn != null && BlockSplitter.makeSeparate(lastInsn.getType())) { if (Consts.DEBUG) { diff --git a/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java b/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java index fa742342..b775fc6b 100644 --- a/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java @@ -162,9 +162,6 @@ public class DebugUtils { if (insn.getType() == InsnType.PHI) { PhiInsn phi = (PhiInsn) insn; phis.add(phi); - if (phi.getArgsCount() != phi.getBlockBinds().size()) { - throw new JadxRuntimeException("Incorrect args and binds in PHI"); - } if (phi.getArgsCount() == 0) { throw new JadxRuntimeException("No args and binds in PHI"); } -- GitLab