Commit 69252ce7 authored by Skylot's avatar Skylot

core: fix processing 'try/catch' in 'if' block

parent df115251
......@@ -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 = traverseIterativeStepInternal(mth, visitor, mth.getRegion());
if (k++ > ITERATIVE_LIMIT) {
throw new JadxOverflowException("Iterative traversal limit reached, method: " + mth);
}
} while (repeat);
}
public static void traverseIterative(MethodNode mth, IRegionIterativeVisitor visitor) {
public static void traverseIncludingExcHandlers(MethodNode mth, IRegionIterativeVisitor visitor) {
boolean repeat;
int k = 0;
do {
repeat = traverseIterativeInternal(mth, visitor, mth.getRegion());
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;
}
}
......
......@@ -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<BlockNode, TryCatchBlock> tryBlocksMap = new HashMap<BlockNode, TryCatchBlock>(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<BlockNode, TryCatchBlock> tryBlocksMap) {
......@@ -105,7 +102,7 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor {
}
}
private static void checkAndWrap(MethodNode mth, Map<BlockNode, TryCatchBlock> tryBlocksMap, IRegion region) {
private static boolean checkAndWrap(MethodNode mth, Map<BlockNode, TryCatchBlock> tryBlocksMap, IRegion region) {
// search dominator blocks in this region (don't need to go deeper)
for (Map.Entry<BlockNode, TryCatchBlock> 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<IContainer> subBlocks = region.getSubBlocks();
Region tryRegion = new Region(replaceRegion);
List<IContainer> 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());
......
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) {"));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment