fix: additional checks for default switch case exit (#2351)

This commit is contained in:
Skylot
2024-11-24 18:19:33 +00:00
parent 45df80f036
commit baa93bad63
3 changed files with 44 additions and 9 deletions
@@ -58,7 +58,7 @@ final class SwitchRegionMaker {
currentRegion.getSubBlocks().add(sw);
stack.push(sw);
BlockNode out = calcSwitchOut(block, stack);
BlockNode out = calcSwitchOut(block, insn, stack);
stack.addExit(out);
processFallThroughCases(sw, out, stack, blocksMap);
@@ -122,7 +122,7 @@ final class SwitchRegionMaker {
return BlockUtils.bitSetToOneBlock(mth, caseExits);
}
private @Nullable BlockNode calcSwitchOut(BlockNode block, RegionStack stack) {
private @Nullable BlockNode calcSwitchOut(BlockNode block, SwitchInsn insn, RegionStack stack) {
// union of case blocks dominance frontier
// works if no fallthrough cases and no returns inside switch
BitSet outs = BlockUtils.newBlocksBitSet(mth);
@@ -184,11 +184,9 @@ final class SwitchRegionMaker {
// check if all returns are equals and should be treated as single out block
return allSameReturns(stack);
}
if (out != imPostDom && !mth.isPreExitBlock(imPostDom)) {
// stop other paths at common exit
stack.addExit(imPostDom);
}
if (block.getCleanSuccessors().contains(imPostDom)) {
if (imPostDom == insn.getDefTargetBlock()
&& block.getCleanSuccessors().contains(imPostDom)
&& block.getDomFrontier().get(imPostDom.getId())) {
// add exit to stop on empty 'default' block
stack.addExit(imPostDom);
}
@@ -343,5 +341,4 @@ final class SwitchRegionMaker {
}
return inserted;
}
}
@@ -513,7 +513,7 @@ public abstract class IntegrationTest extends TestUtils {
}
private void saveToJar(List<File> files, Path baseDir) throws IOException {
Path jarFile = Files.createTempFile(testDir, "tests-" + getTestName() + '-', ".jar");
Path jarFile = Files.createTempFile("tests-" + getTestName() + '-', ".jar");
try (JarOutputStream jar = new JarOutputStream(Files.newOutputStream(jarFile))) {
for (File file : files) {
Path fullPath = file.toPath();
@@ -0,0 +1,38 @@
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 TestSwitchInLoop5 extends IntegrationTest {
public static class TestCls {
private static int test(int r) {
int i;
while (true) {
switch (r) {
case 42:
i = 32;
break;
case 52:
i = 42;
break;
default:
System.out.println("Default switch case");
return 1;
}
r = i;
}
}
}
@Test
public void test() {
assertThat(getClassNode(TestCls.class))
.code()
.containsOne("default:")
.containsOne("System.out.println(");
}
}