fix: improve handler path check for regions

This commit is contained in:
Skylot
2026-04-19 20:32:14 +01:00
parent 169ad2901f
commit bd1c3fffde
3 changed files with 44 additions and 24 deletions
@@ -117,12 +117,12 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor {
return true;
}
private static boolean isHandlerPath(TryCatchBlockAttr tb, IContainer cont) {
private static boolean isHandlerPath(TryCatchBlockAttr tb, IContainer container) {
for (ExceptionHandler h : tb.getHandlers()) {
BlockNode handlerBlock = h.getHandlerBlock();
if (handlerBlock != null
&& !handlerBlock.contains(AFlag.REMOVE)
&& RegionUtils.hasPathThroughBlock(handlerBlock, cont)) {
&& RegionUtils.isPathExists(handlerBlock, container)) {
return true;
}
}
@@ -25,6 +25,8 @@ import jadx.core.dex.nodes.IRegion;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.regions.Region;
import jadx.core.dex.regions.SwitchRegion;
import jadx.core.dex.regions.TryCatchRegion;
import jadx.core.dex.regions.loops.LoopRegion;
import jadx.core.dex.trycatch.CatchAttr;
import jadx.core.dex.trycatch.ExceptionHandler;
@@ -109,19 +111,31 @@ public class RegionUtils {
}
return null;
}
if (container instanceof IBranchRegion) {
return null;
if (container instanceof IConditionRegion) {
return ListUtils.firstOrNull(((IConditionRegion) container).getConditionBlocks());
}
if (container instanceof TryCatchRegion) {
return getFirstBlockNode(((TryCatchRegion) container).getTryRegion());
}
if (container instanceof SwitchRegion) {
return ((SwitchRegion) container).getHeader();
}
if (container instanceof IRegion) {
List<IContainer> blocks = ((IRegion) container).getSubBlocks();
if (blocks.isEmpty()) {
return null;
}
return getFirstBlockNode(blocks.get(0));
return getFirstBlockNode(((IRegion) container).getSubBlocks());
}
throw new JadxRuntimeException(unknownContainerType(container));
}
private static @Nullable BlockNode getFirstBlockNode(List<IContainer> containers) {
for (IContainer cont : containers) {
BlockNode firstBlockNode = getFirstBlockNode(cont);
if (firstBlockNode != null) {
return firstBlockNode;
}
}
return null;
}
public static int getFirstSourceLine(IContainer container) {
if (container instanceof IBlock) {
return BlockUtils.getFirstSourceLine((IBlock) container);
@@ -586,6 +600,18 @@ public class RegionUtils {
throw new JadxRuntimeException(unknownContainerType(cont));
}
/**
* Check if path exists from block to container start.
* Return false if block is inside container.
*/
public static boolean isPathExists(BlockNode block, IContainer container) {
BlockNode firstBlock = RegionUtils.getFirstBlockNode(container);
if (firstBlock != null) {
return BlockUtils.isPathExists(block, firstBlock);
}
return false;
}
protected static String unknownContainerType(IContainer container) {
if (container == null) {
return "Null container variable";
@@ -8,10 +8,12 @@ import org.junit.jupiter.api.Test;
import jadx.NotYetImplemented;
import jadx.tests.api.IntegrationTest;
import jadx.tests.api.utils.assertj.JadxAssertions;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
public class TestTryCatchFinally8 extends IntegrationTest {
@SuppressWarnings({ "ResultOfMethodCallIgnored", "TryFinallyCanBeTryWithResources", "DataFlowIssue" })
public static class TestCls {
public Object test(Object obj) {
File file = new File("r");
@@ -42,20 +44,12 @@ public class TestTryCatchFinally8 extends IntegrationTest {
@Test
@NotYetImplemented("Fix merged catch blocks (shared code between catches)")
public void test() {
JadxAssertions.assertThat(getClassNode(TestCls.class))
assertThat(getClassNode(TestCls.class))
.code()
.contains("try {")
.contains("} catch (IOException e) {")
.contains("} finally {")
.contains("file.delete();");
}
@Test
public void test2() {
disableCompilation();
JadxAssertions.assertThat(getClassNode(TestCls.class))
.code()
.contains("output = new FileOutputStream(file);")
.contains("} catch (IOException e) {");
.containsOne("FileOutputStream output = null;")
.countString(2, "try {")
.countString(2, "} catch (IOException e")
.containsOne("} finally {")
.containsOne("file.delete();");
}
}