core: fix processing 'try/catch' in 'if' block
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+24
-21
@@ -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());
|
||||
|
||||
@@ -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) {"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user