From 5502d93cd57075c2fd810d38d80d040c39c674ee Mon Sep 17 00:00:00 2001 From: Skylot Date: Tue, 4 Feb 2020 18:45:27 +0000 Subject: [PATCH] fix: additional checks before insert move to help type inference (#843) --- .../java/jadx/core/dex/nodes/MethodNode.java | 8 +-- .../debuginfo/DebugInfoApplyVisitor.java | 2 +- .../typeinference/TypeInferenceVisitor.java | 71 ++++++++++++------- 3 files changed, 50 insertions(+), 31 deletions(-) diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java index 06e11ec2d..bfda66775 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java @@ -208,7 +208,7 @@ public class MethodNode extends LineAttrNode implements ILoadable, ICodeNode { } return argsTypes; } catch (Exception e) { - addWarningComment("Failed to parse method signature: " + sp.getSignature(), e); + addWarnComment("Failed to parse method signature: " + sp.getSignature(), e); return null; } } @@ -698,11 +698,11 @@ public class MethodNode extends LineAttrNode implements ILoadable, ICodeNode { ErrorsCounter.methodWarn(this, warnStr); } - public void addWarningComment(String warn) { - addWarningComment(warn, null); + public void addWarnComment(String warn) { + addWarnComment(warn, null); } - public void addWarningComment(String warn, @Nullable Throwable exc) { + public void addWarnComment(String warn, @Nullable Throwable exc) { String commentStr = "JADX WARN: " + warn; addAttr(AType.COMMENTS, commentStr); if (exc != null) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/debuginfo/DebugInfoApplyVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/debuginfo/DebugInfoApplyVisitor.java index d1c7f101c..726aa4a12 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/debuginfo/DebugInfoApplyVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/debuginfo/DebugInfoApplyVisitor.java @@ -64,7 +64,7 @@ public class DebugInfoApplyVisitor extends AbstractVisitor { mth.getSVars().forEach(var -> { ArgType type = var.getTypeInfo().getType(); if (!type.isTypeKnown()) { - mth.addComment("JADX WARNING: type inference failed for: " + var.getDetailedVarInfo(mth)); + mth.addWarnComment("Type inference failed for: " + var.getDetailedVarInfo(mth)); } }); } 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 f0b3aeef3..888aa4039 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 @@ -72,7 +72,9 @@ public final class TypeInferenceVisitor extends AbstractVisitor { if (!resolved) { boolean moveAdded = false; for (SSAVar var : new ArrayList<>(mth.getSVars())) { - moveAdded |= tryInsertAdditionalInsn(mth, var); + if (tryInsertAdditionalInsn(mth, var)) { + moveAdded = true; + } } if (moveAdded) { InitCodeVariables.rerun(mth); @@ -361,50 +363,67 @@ public final class TypeInferenceVisitor extends AbstractVisitor { } } for (PhiInsn phiInsn : usedInPhiList) { - if (!insertMoveForPhi(mth, phiInsn, var)) { + if (!insertMoveForPhi(mth, phiInsn, var, false)) { return false; } } + + // all check passed => apply + for (PhiInsn phiInsn : usedInPhiList) { + insertMoveForPhi(mth, phiInsn, var, true); + } + mth.addComment("JADX INFO: additional move instructions added (" + usedInPhiList.size() + ") to help type inference"); return true; } - private boolean insertMoveForPhi(MethodNode mth, PhiInsn phiInsn, SSAVar var) { + private boolean insertMoveForPhi(MethodNode mth, PhiInsn phiInsn, SSAVar var, boolean apply) { int argsCount = phiInsn.getArgsCount(); for (int argIndex = 0; argIndex < argsCount; argIndex++) { RegisterArg reg = phiInsn.getArg(argIndex); if (reg.getSVar() == var) { - BlockNode blockNode = phiInsn.getBlockByArgIndex(argIndex); - InsnNode lastInsn = BlockUtils.getLastInsn(blockNode); - if (lastInsn != null && BlockSplitter.isSeparate(lastInsn.getType())) { - // can't insert move in block with separate instruction - // trying previous block - List preds = blockNode.getPredecessors(); - if (preds.size() == 1) { - blockNode = preds.get(0); - } else { - mth.addWarn("Failed to insert additional move for type inference"); - return false; - } + BlockNode startBlock = phiInsn.getBlockByArgIndex(argIndex); + BlockNode blockNode = checkBlockForInsnInsert(startBlock); + if (blockNode == null) { + mth.addWarnComment("Failed to insert an additional move for type inference into block " + startBlock); + return false; } + if (apply) { + int regNum = reg.getRegNum(); + RegisterArg resultArg = reg.duplicate(regNum, null); + SSAVar newSsaVar = mth.makeNewSVar(regNum, resultArg); + RegisterArg arg = reg.duplicate(regNum, var); - int regNum = reg.getRegNum(); - RegisterArg resultArg = reg.duplicate(regNum, null); - SSAVar newSsaVar = mth.makeNewSVar(regNum, resultArg); - RegisterArg arg = reg.duplicate(regNum, var); + InsnNode moveInsn = new InsnNode(InsnType.MOVE, 1); + moveInsn.setResult(resultArg); + moveInsn.addArg(arg); + moveInsn.add(AFlag.SYNTHETIC); + blockNode.getInstructions().add(moveInsn); - InsnNode moveInsn = new InsnNode(InsnType.MOVE, 1); - moveInsn.setResult(resultArg); - moveInsn.addArg(arg); - moveInsn.add(AFlag.SYNTHETIC); - blockNode.getInstructions().add(moveInsn); - - phiInsn.replaceArg(reg, reg.duplicate(regNum, newSsaVar)); + phiInsn.replaceArg(reg, reg.duplicate(regNum, newSsaVar)); + } return true; } } return false; } + @Nullable + private BlockNode checkBlockForInsnInsert(BlockNode blockNode) { + if (blockNode.isSynthetic()) { + return null; + } + InsnNode lastInsn = BlockUtils.getLastInsn(blockNode); + if (lastInsn != null && BlockSplitter.isSeparate(lastInsn.getType())) { + // can't insert move in a block with 'separate' instruction => try previous block by simple path + List preds = blockNode.getPredecessors(); + if (preds.size() == 1) { + return checkBlockForInsnInsert(preds.get(0)); + } + return null; + } + return blockNode; + } + private boolean tryWiderObjects(MethodNode mth, SSAVar var) { Set objTypes = new LinkedHashSet<>(); for (ITypeBound bound : var.getTypeInfo().getBounds()) {