diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/DepthRegionTraversal.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/DepthRegionTraversal.java index 513f57646..58164ab3d 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/DepthRegionTraversal.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/DepthRegionTraversal.java @@ -18,18 +18,30 @@ public class DepthRegionTraversal { traverseInternal(mth, visitor, mth.getRegion()); } - public static void traverseIncludingExcHandlers(MethodNode mth, IRegionVisitor visitor) { - traverseInternal(mth, visitor, mth.getRegion()); - for (ExceptionHandler h : mth.getExceptionHandlers()) { - traverseInternal(mth, visitor, h.getHandlerRegion()); - } - } - public static void traverseIterative(MethodNode mth, IRegionIterativeVisitor visitor) { boolean repeat; int k = 0; do { - repeat = traverseIterativeInternal(mth, visitor, mth.getRegion()); + repeat = traverseIterativeStepInternal(mth, visitor, mth.getRegion()); + if (k++ > ITERATIVE_LIMIT) { + throw new JadxOverflowException("Iterative traversal limit reached, method: " + mth); + } + } while (repeat); + } + + public static void traverseIncludingExcHandlers(MethodNode mth, IRegionIterativeVisitor visitor) { + boolean repeat; + int k = 0; + do { + repeat = traverseIterativeStepInternal(mth, visitor, mth.getRegion()); + if (!repeat) { + for (ExceptionHandler h : mth.getExceptionHandlers()) { + repeat = traverseIterativeStepInternal(mth, visitor, h.getHandlerRegion()); + if (repeat) { + break; + } + } + } if (k++ > ITERATIVE_LIMIT) { throw new JadxOverflowException("Iterative traversal limit reached, method: " + mth); } @@ -49,7 +61,7 @@ public class DepthRegionTraversal { } } - private static boolean traverseIterativeInternal(MethodNode mth, IRegionIterativeVisitor visitor, + private static boolean traverseIterativeStepInternal(MethodNode mth, IRegionIterativeVisitor visitor, IContainer container) { if (container instanceof IRegion) { IRegion region = (IRegion) container; @@ -57,7 +69,7 @@ public class DepthRegionTraversal { return true; } for (IContainer subCont : region.getSubBlocks()) { - if (traverseIterativeInternal(mth, visitor, subCont)) { + if (traverseIterativeStepInternal(mth, visitor, subCont)) { return true; } } 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 51e504dcf..634e89da4 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 @@ -2,6 +2,7 @@ package jadx.core.dex.visitors.regions; import jadx.core.dex.attributes.AType; import jadx.core.dex.nodes.BlockNode; +import jadx.core.dex.nodes.IBranchRegion; import jadx.core.dex.nodes.IContainer; import jadx.core.dex.nodes.IRegion; import jadx.core.dex.nodes.MethodNode; @@ -42,18 +43,14 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor { final Map tryBlocksMap = new HashMap(2); searchTryCatchDominators(mth, tryBlocksMap); - int k = 0; - while (!tryBlocksMap.isEmpty()) { - DepthRegionTraversal.traverseIncludingExcHandlers(mth, new AbstractRegionVisitor() { - @Override - public void leaveRegion(MethodNode mth, IRegion region) { - checkAndWrap(mth, tryBlocksMap, region); - } - }); - if (k++ > 100) { - throw new JadxRuntimeException("Try/catch wrap count limit reached in " + mth); + IRegionIterativeVisitor visitor = new IRegionIterativeVisitor() { + @Override + public boolean visitRegion(MethodNode mth, IRegion region) { + boolean changed = checkAndWrap(mth, tryBlocksMap, region); + return changed && !tryBlocksMap.isEmpty(); } - } + }; + DepthRegionTraversal.traverseIncludingExcHandlers(mth, visitor); } private static void searchTryCatchDominators(MethodNode mth, Map tryBlocksMap) { @@ -105,7 +102,7 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor { } } - private static void checkAndWrap(MethodNode mth, Map tryBlocksMap, IRegion region) { + private static boolean checkAndWrap(MethodNode mth, Map tryBlocksMap, IRegion region) { // search dominator blocks in this region (don't need to go deeper) for (Map.Entry entry : tryBlocksMap.entrySet()) { BlockNode dominator = entry.getKey(); @@ -115,23 +112,29 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor { ErrorsCounter.methodError(mth, "Can't wrap try/catch for " + region); } tryBlocksMap.remove(dominator); - return; + return true; } } + return false; } /** * Extract all block dominated by 'dominator' to separate region and mark as try/catch block */ private static boolean wrapBlocks(IRegion replaceRegion, TryCatchBlock tb, BlockNode dominator) { - IRegion region = replaceRegion; - if (region instanceof LoopRegion) { - LoopRegion loop = (LoopRegion) region; - region = loop.getBody(); + if (replaceRegion == null) { + return false; + } + if (replaceRegion instanceof LoopRegion) { + LoopRegion loop = (LoopRegion) replaceRegion; + return wrapBlocks(loop.getBody(), tb, dominator); + } + if (replaceRegion instanceof IBranchRegion) { + return wrapBlocks(replaceRegion.getParent(), tb, dominator); } - Region tryRegion = new Region(region); - List subBlocks = region.getSubBlocks(); + Region tryRegion = new Region(replaceRegion); + List subBlocks = replaceRegion.getSubBlocks(); for (IContainer cont : subBlocks) { if (RegionUtils.isDominatedBy(dominator, cont)) { if (isHandlerPath(tb, cont)) { @@ -144,13 +147,13 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor { return false; } - TryCatchRegion tryCatchRegion = new TryCatchRegion(region, tryRegion); + TryCatchRegion tryCatchRegion = new TryCatchRegion(replaceRegion, tryRegion); tryRegion.setParent(tryCatchRegion); tryCatchRegion.setTryCatchBlock(tb.getCatchAttr().getTryBlock()); // replace first node by region IContainer firstNode = tryRegion.getSubBlocks().get(0); - if (!region.replaceSubBlock(firstNode, tryCatchRegion)) { + if (!replaceRegion.replaceSubBlock(firstNode, tryCatchRegion)) { return false; } subBlocks.removeAll(tryRegion.getSubBlocks()); diff --git a/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchInIf.java b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchInIf.java new file mode 100644 index 000000000..79918cb10 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatchInIf.java @@ -0,0 +1,52 @@ +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.assertEquals; +import static org.junit.Assert.assertThat; + +public class TestTryCatchInIf extends IntegrationTest { + + public static class TestCls { + + private String test(String name, String value) { + if (value != null) { + try { + int key; + if (value.startsWith("0x")) { + value = value.substring(2); + key = Integer.parseInt(value, 16); + } else { + key = Integer.parseInt(value); + } + return name + "=" + key; + } catch (NumberFormatException e) { + return "Failed to parse number"; + } + } + System.out.println("?"); + return null; + } + + public void check() { + assertEquals(null, test("n", null)); + assertEquals("n=7", test("n", "7")); + assertEquals("n=77", test("n", "0x" + Integer.toHexString(77))); + assertEquals("Failed to parse number", test("n", "abc")); + assertEquals("Failed to parse number", test("n", "0xabX")); + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, containsOne("try {")); + assertThat(code, containsOne("} catch (NumberFormatException e) {")); + } +}