diff --git a/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java b/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java index 19c557ffb..02c74da92 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java +++ b/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java @@ -292,7 +292,7 @@ public class CodeWriter { out = new PrintWriter(file, "UTF-8"); String code = buf.toString(); code = removeFirstEmptyLine(code); - out.print(code); + out.println(code); } catch (Exception e) { LOG.error("Save file error", e); } finally { diff --git a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java index bd43ba626..da08e8eb8 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -436,14 +436,6 @@ public class InsnGen { } break; - case MOVE_EXCEPTION: - if (isFallback()) { - code.add("move-exception"); - } else { - addArg(code, insn.getArg(0)); - } - break; - case TERNARY: makeTernary((TernaryInsn) insn, code, state); break; @@ -472,6 +464,11 @@ public class InsnGen { code.add("goto ").add(MethodGen.getLabelName(((GotoNode) insn).getTarget())); break; + case MOVE_EXCEPTION: + assert isFallback(); + code.add("move-exception"); + break; + case SWITCH: assert isFallback(); SwitchNode sw = (SwitchNode) insn; diff --git a/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java b/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java index 15d78f76f..409fa3ae9 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java @@ -9,6 +9,7 @@ import jadx.core.dex.info.FieldInfo; import jadx.core.dex.instructions.IndexInsnNode; import jadx.core.dex.instructions.SwitchNode; import jadx.core.dex.instructions.args.InsnArg; +import jadx.core.dex.instructions.args.NamedArg; import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.FieldNode; @@ -19,13 +20,13 @@ import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.regions.Region; import jadx.core.dex.regions.SwitchRegion; import jadx.core.dex.regions.SynchronizedRegion; +import jadx.core.dex.regions.TryCatchRegion; import jadx.core.dex.regions.conditions.IfCondition; import jadx.core.dex.regions.conditions.IfRegion; import jadx.core.dex.regions.loops.ForEachLoop; import jadx.core.dex.regions.loops.ForLoop; import jadx.core.dex.regions.loops.LoopRegion; import jadx.core.dex.regions.loops.LoopType; -import jadx.core.dex.trycatch.CatchAttr; import jadx.core.dex.trycatch.ExceptionHandler; import jadx.core.dex.trycatch.TryCatchBlock; import jadx.core.utils.ErrorsCounter; @@ -59,6 +60,8 @@ public class RegionGen extends InsnGen { makeSwitch((SwitchRegion) cont, code); } else if (cont instanceof LoopRegion) { makeLoop((LoopRegion) cont, code); + } else if (cont instanceof TryCatchRegion) { + makeTryCatch((TryCatchRegion) cont, code); } else if (cont instanceof SynchronizedRegion) { makeSynchronizedRegion((SynchronizedRegion) cont, code); } @@ -80,14 +83,9 @@ public class RegionGen extends InsnGen { } private void makeSimpleRegion(CodeWriter code, Region region) throws CodegenException { - CatchAttr tc = region.get(AType.CATCH_BLOCK); - if (tc != null) { - makeTryCatch(region, tc.getTryBlock(), code); - } else { - declareVars(code, region); - for (IContainer c : region.getSubBlocks()) { - makeRegion(code, c); - } + declareVars(code, region); + for (IContainer c : region.getSubBlocks()) { + makeRegion(code, c); } } @@ -283,11 +281,11 @@ public class RegionGen extends InsnGen { } } - private void makeTryCatch(IContainer region, TryCatchBlock tryCatchBlock, CodeWriter code) - throws CodegenException { + private void makeTryCatch(TryCatchRegion region, CodeWriter code) throws CodegenException { + TryCatchBlock tryCatchBlock = region.geTryCatchBlock(); code.startLine("try {"); - region.remove(AType.CATCH_BLOCK); - makeRegionIndent(code, region); + makeRegionIndent(code, region.getTryRegion()); + // TODO: move search of 'allHandler' to 'TryCatchRegion' ExceptionHandler allHandler = null; for (ExceptionHandler handler : tryCatchBlock.getHandlers()) { if (!handler.isCatchAll()) { @@ -309,20 +307,25 @@ public class RegionGen extends InsnGen { code.startLine('}'); } - private void makeCatchBlock(CodeWriter code, ExceptionHandler handler) - throws CodegenException { + private void makeCatchBlock(CodeWriter code, ExceptionHandler handler) throws CodegenException { IContainer region = handler.getHandlerRegion(); - if (region != null) { - code.startLine("} catch ("); + if (region == null) { + return; + } + code.startLine("} catch ("); + InsnArg arg = handler.getArg(); + if (arg instanceof RegisterArg) { + declareVar(code, (RegisterArg) arg); + } else if (arg instanceof NamedArg) { if (handler.isCatchAll()) { code.add("Throwable"); } else { useClass(code, handler.getCatchType()); } code.add(' '); - code.add(mgen.getNameGen().assignNamedArg(handler.getArg())); - code.add(") {"); - makeRegionIndent(code, region); + code.add(mgen.getNameGen().assignNamedArg((NamedArg) arg)); } + code.add(") {"); + makeRegionIndent(code, region); } } diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java b/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java index a0eccdcf7..3f750b52c 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java @@ -4,7 +4,6 @@ import jadx.core.dex.info.FieldInfo; import jadx.core.dex.info.MethodInfo; import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.InsnArg; -import jadx.core.dex.instructions.args.NamedArg; import jadx.core.dex.instructions.args.PrimitiveType; import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.nodes.DexNode; @@ -404,8 +403,7 @@ public class InsnDecoder { case Opcodes.MOVE_EXCEPTION: return insn(InsnType.MOVE_EXCEPTION, - InsnArg.reg(insn, 0, ArgType.unknown(PrimitiveType.OBJECT)), - new NamedArg("e", ArgType.unknown(PrimitiveType.OBJECT))); + InsnArg.reg(insn, 0, ArgType.unknown(PrimitiveType.OBJECT))); case Opcodes.RETURN_VOID: return new InsnNode(InsnType.RETURN, 0); diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/InsnArg.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/InsnArg.java index 989d862b7..cf49e4782 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/InsnArg.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/InsnArg.java @@ -30,8 +30,8 @@ public abstract class InsnArg extends Typed { return reg(InsnUtils.getArg(insn, argNum), type); } - public static MthParameterArg parameterReg(int regNum, ArgType type) { - return new MthParameterArg(regNum, type); + public static TypeImmutableArg typeImmutableReg(int regNum, ArgType type) { + return new TypeImmutableArg(regNum, type); } public static LiteralArg lit(long literal, ArgType type) { diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/MthParameterArg.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/TypeImmutableArg.java similarity index 81% rename from jadx-core/src/main/java/jadx/core/dex/instructions/args/MthParameterArg.java rename to jadx-core/src/main/java/jadx/core/dex/instructions/args/TypeImmutableArg.java index 275486e8f..850aa61d8 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/MthParameterArg.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/TypeImmutableArg.java @@ -1,10 +1,10 @@ package jadx.core.dex.instructions.args; -public class MthParameterArg extends RegisterArg { +public class TypeImmutableArg extends RegisterArg { private boolean isThis; - public MthParameterArg(int rn, ArgType type) { + public TypeImmutableArg(int rn, ArgType type) { super(rn, type); } @@ -48,13 +48,13 @@ public class MthParameterArg extends RegisterArg { if (this == obj) { return true; } - if (!(obj instanceof MthParameterArg)) { + if (!(obj instanceof TypeImmutableArg)) { return false; } if (!super.equals(obj)) { return false; } - MthParameterArg that = (MthParameterArg) obj; + TypeImmutableArg that = (TypeImmutableArg) obj; return isThis == that.isThis; } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/IContainer.java b/jadx-core/src/main/java/jadx/core/dex/nodes/IContainer.java index cbf87f77b..71e33e277 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/IContainer.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/IContainer.java @@ -4,6 +4,8 @@ import jadx.core.dex.attributes.IAttributeNode; public interface IContainer extends IAttributeNode { - // unique id for use in 'toString()' method + /** + * Unique id for use in 'toString()' method + */ String baseString(); } 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 3a94344e3..0af32cf99 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 @@ -170,7 +170,6 @@ public class InsnNode extends LineAttrNode { case NEW_ARRAY: case NEW_MULTIDIM_ARRAY: case STR_CONCAT: - case MOVE_EXCEPTION: return true; default: 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 540f92cbd..3ac3aa825 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 @@ -15,9 +15,9 @@ import jadx.core.dex.instructions.InsnDecoder; import jadx.core.dex.instructions.SwitchNode; import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.InsnArg; -import jadx.core.dex.instructions.args.MthParameterArg; import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.instructions.args.SSAVar; +import jadx.core.dex.instructions.args.TypeImmutableArg; import jadx.core.dex.nodes.parser.SignatureParser; import jadx.core.dex.regions.Region; import jadx.core.dex.trycatch.ExcHandlerAttr; @@ -183,7 +183,7 @@ public class MethodNode extends LineAttrNode implements ILoadable { if (accFlags.isStatic()) { thisArg = null; } else { - MthParameterArg arg = InsnArg.parameterReg(pos - 1, parentClass.getClassInfo().getType()); + TypeImmutableArg arg = InsnArg.typeImmutableReg(pos - 1, parentClass.getClassInfo().getType()); arg.markAsThis(); thisArg = arg; } @@ -193,7 +193,7 @@ public class MethodNode extends LineAttrNode implements ILoadable { } argsList = new ArrayList(args.size()); for (ArgType arg : args) { - argsList.add(InsnArg.parameterReg(pos, arg)); + argsList.add(InsnArg.typeImmutableReg(pos, arg)); pos += arg.getRegCount(); } } diff --git a/jadx-core/src/main/java/jadx/core/dex/regions/TryCatchRegion.java b/jadx-core/src/main/java/jadx/core/dex/regions/TryCatchRegion.java new file mode 100644 index 000000000..0f4699bb1 --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/dex/regions/TryCatchRegion.java @@ -0,0 +1,62 @@ +package jadx.core.dex.regions; + +import jadx.core.dex.nodes.IContainer; +import jadx.core.dex.nodes.IRegion; +import jadx.core.dex.trycatch.ExceptionHandler; +import jadx.core.dex.trycatch.TryCatchBlock; +import jadx.core.utils.Utils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public final class TryCatchRegion extends AbstractRegion { + + private final IContainer tryRegion; + private List catchRegions = Collections.emptyList(); + private TryCatchBlock tryCatchBlock; + + public TryCatchRegion(IRegion parent, IContainer tryRegion) { + super(parent); + this.tryRegion = tryRegion; + } + + public IContainer getTryRegion() { + return tryRegion; + } + + public List getCatchRegions() { + return catchRegions; + } + + public TryCatchBlock geTryCatchBlock() { + return tryCatchBlock; + } + + public void setTryCatchBlock(TryCatchBlock tryCatchBlock) { + this.tryCatchBlock = tryCatchBlock; + this.catchRegions = new ArrayList(tryCatchBlock.getHandlersCount()); + for (ExceptionHandler handler : tryCatchBlock.getHandlers()) { + catchRegions.add(handler.getHandlerRegion()); + } + } + + @Override + public List getSubBlocks() { + List all = new ArrayList(1 + catchRegions.size()); + all.add(tryRegion); + all.addAll(catchRegions); + return Collections.unmodifiableList(all); + } + + @Override + public String baseString() { + return tryRegion.baseString(); + } + + @Override + public String toString() { + return "Try: " + tryRegion + + " catches: " + Utils.listToString(catchRegions); + } +} diff --git a/jadx-core/src/main/java/jadx/core/dex/trycatch/ExceptionHandler.java b/jadx-core/src/main/java/jadx/core/dex/trycatch/ExceptionHandler.java index 347c37f59..f4139b2c9 100644 --- a/jadx-core/src/main/java/jadx/core/dex/trycatch/ExceptionHandler.java +++ b/jadx-core/src/main/java/jadx/core/dex/trycatch/ExceptionHandler.java @@ -2,7 +2,7 @@ package jadx.core.dex.trycatch; import jadx.core.Consts; import jadx.core.dex.info.ClassInfo; -import jadx.core.dex.instructions.args.NamedArg; +import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.IContainer; import jadx.core.utils.InsnUtils; @@ -18,7 +18,7 @@ public class ExceptionHandler { private BlockNode handlerBlock; private final List blocks = new ArrayList(); private IContainer handlerRegion; - private NamedArg arg; + private InsnArg arg; private TryCatchBlock tryBlock; @@ -63,11 +63,11 @@ public class ExceptionHandler { this.handlerRegion = handlerRegion; } - public NamedArg getArg() { + public InsnArg getArg() { return arg; } - public void setArg(NamedArg arg) { + public void setArg(InsnArg arg) { this.arg = arg; } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/BlockProcessingHelper.java b/jadx-core/src/main/java/jadx/core/dex/visitors/BlockProcessingHelper.java index 7a8052ece..46c0ae730 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/BlockProcessingHelper.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/BlockProcessingHelper.java @@ -4,7 +4,7 @@ import jadx.core.dex.attributes.AType; import jadx.core.dex.instructions.IfNode; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.args.ArgType; -import jadx.core.dex.instructions.args.NamedArg; +import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.InsnNode; @@ -43,30 +43,24 @@ public class BlockProcessingHelper { * Set exception handler attribute for whole block */ private static void markExceptionHandlers(BlockNode block) { - if (!block.getInstructions().isEmpty()) { - InsnNode me = block.getInstructions().get(0); - ExcHandlerAttr handlerAttr = me.get(AType.EXC_HANDLER); - if (handlerAttr != null && me.getType() == InsnType.MOVE_EXCEPTION) { - ExceptionHandler excHandler = handlerAttr.getHandler(); - assert me.getOffset() == excHandler.getHandleOffset(); - // set correct type for 'move-exception' operation - RegisterArg resArg = me.getResult(); - NamedArg excArg = (NamedArg) me.getArg(0); - ArgType type; - if (excHandler.isCatchAll()) { - type = ArgType.THROWABLE; - excArg.setName("th"); - } else { - type = excHandler.getCatchType().getType(); - excArg.setName("e"); - } - resArg.forceType(type); - excArg.setType(type); - - excHandler.setArg(excArg); - block.addAttr(handlerAttr); - } + if (block.getInstructions().isEmpty()) { + return; } + InsnNode me = block.getInstructions().get(0); + ExcHandlerAttr handlerAttr = me.get(AType.EXC_HANDLER); + if (handlerAttr == null || me.getType() != InsnType.MOVE_EXCEPTION) { + return; + } + ExceptionHandler excHandler = handlerAttr.getHandler(); + block.addAttr(handlerAttr); + // set correct type for 'move-exception' operation + ArgType type = excHandler.isCatchAll() ? ArgType.THROWABLE : excHandler.getCatchType().getType(); + + RegisterArg resArg = me.getResult(); + resArg = InsnArg.reg(resArg.getRegNum(), type); + me.setResult(resArg); + + excHandler.setArg(resArg); } private static void processExceptionHandlers(MethodNode mth, BlockNode block) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/CodeShrinker.java b/jadx-core/src/main/java/jadx/core/dex/visitors/CodeShrinker.java index fef58004c..6edf447bd 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/CodeShrinker.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/CodeShrinker.java @@ -200,7 +200,9 @@ public class CodeShrinker extends AbstractVisitor { continue; } InsnNode assignInsn = sVar.getAssign().getParentInsn(); - if (assignInsn == null || assignInsn instanceof PhiInsn) { + if (assignInsn == null + || assignInsn instanceof PhiInsn + || assignInsn.getType() == InsnType.MOVE_EXCEPTION) { continue; } int assignPos = insnList.getIndex(assignInsn); diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java index b258204d5..82b346c80 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ModVisitor.java @@ -14,7 +14,9 @@ import jadx.core.dex.instructions.SwitchNode; 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.NamedArg; import jadx.core.dex.instructions.args.RegisterArg; +import jadx.core.dex.instructions.args.SSAVar; import jadx.core.dex.instructions.mods.ConstructorInsn; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.ClassNode; @@ -298,9 +300,27 @@ public class ModVisitor extends AbstractVisitor { List blockInsns = block.getInstructions(); if (!blockInsns.isEmpty()) { InsnNode insn = blockInsns.get(0); - if (insn.getType() == InsnType.MOVE_EXCEPTION - && insn.getResult().getSVar().getUseCount() == 0) { - InstructionRemover.remove(mth, block, 0); + if (insn.getType() == InsnType.MOVE_EXCEPTION) { + // result arg used both in this insn and exception handler, + RegisterArg resArg = insn.getResult(); + ArgType type = excHandler.isCatchAll() ? ArgType.THROWABLE : excHandler.getCatchType().getType(); + String name = excHandler.isCatchAll() ? "th" : "e"; + if (resArg.getName() == null) { + resArg.setName(name); + } + SSAVar sVar = insn.getResult().getSVar(); + if (sVar.getUseCount() == 0) { + excHandler.setArg(new NamedArg(name, type)); + InstructionRemover.remove(mth, block, 0); + } else if (sVar.isUsedInPhi()) { + // exception var moved to external variable => replace with 'move' insn + InsnNode moveInsn = new InsnNode(InsnType.MOVE, 1); + moveInsn.setResult(insn.getResult()); + NamedArg namedArg = new NamedArg(name, type); + moveInsn.addArg(namedArg); + excHandler.setArg(namedArg); + replaceInsn(block, 0, moveInsn); + } } } int totalSize = 0; diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/PrepareForCodeGen.java b/jadx-core/src/main/java/jadx/core/dex/visitors/PrepareForCodeGen.java index 37e9c36c8..26167f477 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/PrepareForCodeGen.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/PrepareForCodeGen.java @@ -45,6 +45,7 @@ public class PrepareForCodeGen extends AbstractVisitor { case NOP: case MONITOR_ENTER: case MONITOR_EXIT: + case MOVE_EXCEPTION: it.remove(); break; diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java index 8ab48c04b..71e36106f 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessTryCatchRegions.java @@ -7,6 +7,7 @@ import jadx.core.dex.nodes.IRegion; import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.regions.AbstractRegion; import jadx.core.dex.regions.Region; +import jadx.core.dex.regions.TryCatchRegion; import jadx.core.dex.regions.loops.LoopRegion; import jadx.core.dex.trycatch.CatchAttr; import jadx.core.dex.trycatch.ExceptionHandler; @@ -129,33 +130,36 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor { region = loop.getBody(); } - Region newRegion = new Region(region); + Region tryRegion = new Region(region); List subBlocks = region.getSubBlocks(); for (IContainer cont : subBlocks) { if (RegionUtils.isDominatedBy(dominator, cont)) { if (isHandlerPath(tb, cont)) { break; } - newRegion.getSubBlocks().add(cont); + tryRegion.getSubBlocks().add(cont); } } - if (newRegion.getSubBlocks().isEmpty()) { + if (tryRegion.getSubBlocks().isEmpty()) { return false; } + + TryCatchRegion tryCatchRegion = new TryCatchRegion(region, tryRegion); + tryRegion.setParent(tryCatchRegion); + tryCatchRegion.setTryCatchBlock(tb.getCatchAttr().getTryBlock()); + // replace first node by region - IContainer firstNode = newRegion.getSubBlocks().get(0); - if (!region.replaceSubBlock(firstNode, newRegion)) { + IContainer firstNode = tryRegion.getSubBlocks().get(0); + if (!region.replaceSubBlock(firstNode, tryCatchRegion)) { return false; } - subBlocks.removeAll(newRegion.getSubBlocks()); + subBlocks.removeAll(tryRegion.getSubBlocks()); - newRegion.addAttr(tb.getCatchAttr()); - - // fix parents - for (IContainer cont : newRegion.getSubBlocks()) { + // fix parents for tryRegion sub blocks + for (IContainer cont : tryRegion.getSubBlocks()) { if (cont instanceof AbstractRegion) { AbstractRegion aReg = (AbstractRegion) cont; - aReg.setParent(newRegion); + aReg.setParent(tryRegion); } } return true; diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java index 8321763b4..c3eaef466 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/ProcessVariables.java @@ -4,6 +4,7 @@ import jadx.core.codegen.NameGen; import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.nodes.DeclareVariablesAttr; +import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.RegisterArg; import jadx.core.dex.instructions.args.VarName; @@ -158,6 +159,22 @@ public class ProcessVariables extends AbstractVisitor { usageMap.remove(new Variable(arg)); } + Iterator> umIt = usageMap.entrySet().iterator(); + while (umIt.hasNext()) { + Entry entry = umIt.next(); + Usage u = entry.getValue(); + // if no assigns => remove + if (u.getAssigns().isEmpty()) { + umIt.remove(); + continue; + } + + // variable declared at 'catch' clause + InsnNode parentInsn = u.getArg().getParentInsn(); + if (parentInsn == null || parentInsn.getType() == InsnType.MOVE_EXCEPTION) { + umIt.remove(); + } + } if (usageMap.isEmpty()) { return; } @@ -168,13 +185,6 @@ public class ProcessVariables extends AbstractVisitor { for (Iterator> it = usageMap.entrySet().iterator(); it.hasNext(); ) { Entry entry = it.next(); Usage u = entry.getValue(); - - // if no assigns => remove - if (u.getAssigns().isEmpty()) { - it.remove(); - continue; - } - // check if variable can be declared at current assigns for (IRegion assignRegion : u.getAssigns()) { if (u.getArgRegion() == assignRegion @@ -186,6 +196,9 @@ public class ProcessVariables extends AbstractVisitor { } } } + if (usageMap.isEmpty()) { + return; + } // apply for (Entry entry : usageMap.entrySet()) { @@ -262,7 +275,7 @@ public class ProcessVariables extends AbstractVisitor { } private static int calculateOrder(IContainer container, Map regionsOrder, - int id, boolean inc) { + int id, boolean inc) { if (!(container instanceof IRegion)) { return id; } @@ -299,8 +312,8 @@ public class ProcessVariables extends AbstractVisitor { && isAllRegionsAfter(region, pos, u.getUseRegions(), regionsOrder); } - private static boolean isAllRegionsAfter(IRegion region, Integer pos, - Set regions, Map regionsOrder) { + private static boolean isAllRegionsAfter(IRegion region, int pos, + Set regions, Map regionsOrder) { for (IRegion r : regions) { if (r == region) { continue; @@ -313,7 +326,7 @@ public class ProcessVariables extends AbstractVisitor { if (pos > rPos) { return false; } - if (pos.equals(rPos)) { + if (pos == rPos) { return isAllRegionsAfterRecursive(region, regions); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/TestArgInline.java b/jadx-core/src/test/java/jadx/tests/integration/TestArgInline.java index cd2e69784..b1162934a 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/TestArgInline.java +++ b/jadx-core/src/test/java/jadx/tests/integration/TestArgInline.java @@ -23,10 +23,11 @@ public class TestArgInline extends IntegrationTest { @Test public void test() { + noDebugInfo(); ClassNode cls = getClassNode(TestCls.class); String code = cls.getCode().toString(); - assertThat(code, containsString("a++;")); - assertThat(code, not(containsString("a = a + 1;"))); + assertThat(code, containsString("i++;")); + assertThat(code, not(containsString("i = i + 1;"))); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/others/TestIfTryInCatch.java b/jadx-core/src/test/java/jadx/tests/integration/others/TestIfTryInCatch.java index 5bf7c8ae3..fc8e077e6 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/others/TestIfTryInCatch.java +++ b/jadx-core/src/test/java/jadx/tests/integration/others/TestIfTryInCatch.java @@ -12,7 +12,6 @@ import static org.junit.Assert.assertThat; public class TestIfTryInCatch extends IntegrationTest { public static class TestCls { - private static final String TAG = "TAG"; private Exception exception; private java.lang.Object data; @@ -35,11 +34,11 @@ public class TestIfTryInCatch extends IntegrationTest { } private static boolean b(Object obj) { - return false; + return obj == null; } private static boolean a(Exception e) { - return false; + return e instanceof RuntimeException; } private Object f() { diff --git a/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatch7.java b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatch7.java new file mode 100644 index 000000000..4f7a52df0 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatch7.java @@ -0,0 +1,39 @@ +package jadx.tests.integration.trycatch; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.IntegrationTest; + +import org.junit.Test; + +import static jadx.tests.api.utils.JadxMatchers.containsOne; +import static org.junit.Assert.assertThat; + +public class TestTryCatch7 extends IntegrationTest { + + public static class TestCls { + private Exception test() { + Exception e = new Exception(); + try { + Thread.sleep(50); + } catch (Exception ex) { + e = ex; + } + e.printStackTrace(); + return e; + } + } + + @Test + public void test() { + noDebugInfo(); + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + String excVarName = "exception"; + assertThat(code, containsOne("Exception " + excVarName + " = new Exception();")); + assertThat(code, containsOne("} catch (Exception e) {")); + assertThat(code, containsOne(excVarName + " = e;")); + assertThat(code, containsOne(excVarName + ".printStackTrace();")); + assertThat(code, containsOne("return " + excVarName + ";")); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/integration/variables/TestVariables4.java b/jadx-core/src/test/java/jadx/tests/integration/variables/TestVariables4.java index 38dcc68b4..e21c40caf 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/variables/TestVariables4.java +++ b/jadx-core/src/test/java/jadx/tests/integration/variables/TestVariables4.java @@ -67,4 +67,10 @@ public class TestVariables4 extends IntegrationTest { assertThat(code, containsString("System.err.println(\"Class '\" + clsName + \"' not found\");")); assertThat(code, containsString("return pass;")); } + + @Test + public void test2() { + noDebugInfo(); + getClassNode(TestCls.class); + } }