fix: correct method exit blocks collection (#876)
This commit is contained in:
@@ -58,7 +58,7 @@ public class BlockProcessor extends AbstractVisitor {
|
||||
clearBlocksState(mth);
|
||||
computeDominators(mth);
|
||||
}
|
||||
markReturnBlocks(mth);
|
||||
updateExitBlocks(mth);
|
||||
|
||||
int i = 0;
|
||||
while (modifyBlocksTree(mth)) {
|
||||
@@ -66,7 +66,7 @@ public class BlockProcessor extends AbstractVisitor {
|
||||
clearBlocksState(mth);
|
||||
// recalculate dominators tree
|
||||
computeDominators(mth);
|
||||
markReturnBlocks(mth);
|
||||
updateExitBlocks(mth);
|
||||
|
||||
if (i++ > 100) {
|
||||
mth.addWarn("CFG modification limit reached, blocks count: " + mth.getBasicBlocks().size());
|
||||
@@ -337,12 +337,33 @@ public class BlockProcessor extends AbstractVisitor {
|
||||
block.setDomFrontier(domFrontier);
|
||||
}
|
||||
|
||||
private static void markReturnBlocks(MethodNode mth) {
|
||||
private static void updateExitBlocks(MethodNode mth) {
|
||||
mth.getExitBlocks().clear();
|
||||
mth.getBasicBlocks().forEach(block -> {
|
||||
if (BlockUtils.checkLastInsnType(block, InsnType.RETURN)) {
|
||||
block.add(AFlag.RETURN);
|
||||
mth.getExitBlocks().add(block);
|
||||
boolean noSuccessors = block.getSuccessors().isEmpty();
|
||||
boolean exitBlock = false;
|
||||
InsnNode lastInsn = BlockUtils.getLastInsn(block);
|
||||
if (lastInsn != null) {
|
||||
InsnType insnType = lastInsn.getType();
|
||||
if (insnType == InsnType.RETURN) {
|
||||
block.add(AFlag.RETURN);
|
||||
exitBlock = true;
|
||||
if (!noSuccessors) {
|
||||
throw new JadxRuntimeException("Found a block after RETURN instruction: " + lastInsn + " in block: " + block);
|
||||
}
|
||||
} else if (insnType == InsnType.THROW) {
|
||||
if (noSuccessors) {
|
||||
exitBlock = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exitBlock) {
|
||||
mth.addExitBlock(block);
|
||||
} else if (noSuccessors
|
||||
&& !mth.isVoidReturn()
|
||||
&& !mth.isConstructor()) {
|
||||
mth.addComment("JADX INFO: Unexpected exit block: " + block
|
||||
+ ". Expect last instruction to be RETURN or THROW, got: " + lastInsn);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package jadx.tests.integration.switches;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestSwitchWithThrow extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
public int test(int i) {
|
||||
if (i != 0) {
|
||||
switch (i % 4) {
|
||||
case 1:
|
||||
throw new IllegalStateException("1");
|
||||
case 2:
|
||||
throw new IllegalStateException("2");
|
||||
default:
|
||||
throw new IllegalStateException("Other");
|
||||
}
|
||||
} else {
|
||||
System.out.println("0");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void check() {
|
||||
assertThat(test(0)).isEqualTo(-1);
|
||||
// TODO: implement 'invoke-custom' support
|
||||
// assertThat(catchThrowable(() -> test(1)))
|
||||
// .isInstanceOf(IllegalStateException.class).hasMessageContaining("1");
|
||||
// assertThat(catchThrowable(() -> test(3)))
|
||||
// .isInstanceOf(IllegalStateException.class).hasMessageContaining("Other");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.contains("throw new IllegalStateException(\"1\");");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user