fix: support nested try/finally blocks (#1249)
This commit is contained in:
@@ -69,7 +69,7 @@ public class AttachTryCatchVisitor extends AbstractVisitor {
|
||||
InsnNode insnAtOffset = insnByOffset[offset];
|
||||
if (insnAtOffset != null) {
|
||||
insn = insnAtOffset;
|
||||
insn.addAttr(catchAttr);
|
||||
attachCatchAttr(catchAttr, insn);
|
||||
if (!tryBlockStarted) {
|
||||
insn.add(AFlag.TRY_ENTER);
|
||||
tryBlockStarted = true;
|
||||
@@ -91,6 +91,17 @@ public class AttachTryCatchVisitor extends AbstractVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private static void attachCatchAttr(CatchAttr catchAttr, InsnNode insn) {
|
||||
CatchAttr existAttr = insn.get(AType.EXC_CATCH);
|
||||
if (existAttr != null) {
|
||||
// merge handlers
|
||||
List<ExceptionHandler> handlers = Utils.concat(existAttr.getHandlers(), catchAttr.getHandlers());
|
||||
insn.addAttr(new CatchAttr(handlers));
|
||||
} else {
|
||||
insn.addAttr(catchAttr);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<ExceptionHandler> attachHandlers(MethodNode mth, ICatch catchBlock, InsnNode[] insnByOffset) {
|
||||
int[] handlerOffsetArr = catchBlock.getHandlers();
|
||||
String[] handlerTypes = catchBlock.getTypes();
|
||||
|
||||
@@ -80,6 +80,7 @@ public class MarkFinallyVisitor extends AbstractVisitor {
|
||||
reThrowInsn = BlockUtils.getLastInsn(excBlock);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allHandler != null && reThrowInsn != null) {
|
||||
@@ -108,27 +109,47 @@ public class MarkFinallyVisitor extends AbstractVisitor {
|
||||
BlockNode startBlock = Utils.getOne(handlerBlock.getCleanSuccessors());
|
||||
FinallyExtractInfo extractInfo = new FinallyExtractInfo(allHandler, startBlock, handlerBlocks);
|
||||
|
||||
// collect handlers from this and all inner blocks
|
||||
List<ExceptionHandler> handlers = new ArrayList<>();
|
||||
collectAllHandlers(tryBlock, handlers);
|
||||
|
||||
boolean hasInnerBlocks = !tryBlock.getInnerTryBlocks().isEmpty();
|
||||
List<ExceptionHandler> handlers;
|
||||
if (hasInnerBlocks) {
|
||||
// collect handlers from this and all inner blocks (intentionally not using recursive collect for
|
||||
// now)
|
||||
handlers = new ArrayList<>(tryBlock.getHandlers());
|
||||
for (TryCatchBlockAttr innerTryBlock : tryBlock.getInnerTryBlocks()) {
|
||||
handlers.addAll(innerTryBlock.getHandlers());
|
||||
}
|
||||
} else {
|
||||
handlers = tryBlock.getHandlers();
|
||||
}
|
||||
if (handlers.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// search 'finally' instructions in other handlers
|
||||
if (!handlers.isEmpty()) {
|
||||
for (ExceptionHandler otherHandler : handlers) {
|
||||
if (otherHandler == allHandler) {
|
||||
continue;
|
||||
}
|
||||
for (BlockNode checkBlock : otherHandler.getBlocks()) {
|
||||
if (searchDuplicateInsns(checkBlock, extractInfo)) {
|
||||
break;
|
||||
} else {
|
||||
extractInfo.getFinallyInsnsSlice().resetIncomplete();
|
||||
}
|
||||
for (ExceptionHandler otherHandler : handlers) {
|
||||
if (otherHandler == allHandler) {
|
||||
continue;
|
||||
}
|
||||
for (BlockNode checkBlock : otherHandler.getBlocks()) {
|
||||
if (searchDuplicateInsns(checkBlock, extractInfo)) {
|
||||
break;
|
||||
} else {
|
||||
extractInfo.getFinallyInsnsSlice().resetIncomplete();
|
||||
}
|
||||
}
|
||||
if (extractInfo.getDuplicateSlices().size() != handlers.size() - 1) {
|
||||
}
|
||||
boolean mergeInnerTryBlocks;
|
||||
int duplicatesCount = extractInfo.getDuplicateSlices().size();
|
||||
boolean fullTryBlock = duplicatesCount == (handlers.size() - 1);
|
||||
if (fullTryBlock) {
|
||||
// all collected handlers have duplicate block
|
||||
mergeInnerTryBlocks = hasInnerBlocks;
|
||||
} else {
|
||||
// some handlers don't have duplicated blocks
|
||||
if (!hasInnerBlocks || duplicatesCount != (tryBlock.getHandlers().size() - 1)) {
|
||||
// unexpected count of duplicated slices
|
||||
return false;
|
||||
}
|
||||
mergeInnerTryBlocks = false;
|
||||
}
|
||||
|
||||
// remove 'finally' from 'try' blocks, check all up paths on each exit (connected with finally exit)
|
||||
@@ -166,9 +187,8 @@ public class MarkFinallyVisitor extends AbstractVisitor {
|
||||
apply(extractInfo);
|
||||
allHandler.setFinally(true);
|
||||
|
||||
// merge inner try blocks
|
||||
List<TryCatchBlockAttr> innerTryBlocks = tryBlock.getInnerTryBlocks();
|
||||
if (!innerTryBlocks.isEmpty()) {
|
||||
if (mergeInnerTryBlocks) {
|
||||
List<TryCatchBlockAttr> innerTryBlocks = tryBlock.getInnerTryBlocks();
|
||||
for (TryCatchBlockAttr innerTryBlock : innerTryBlocks) {
|
||||
tryBlock.getHandlers().addAll(innerTryBlock.getHandlers());
|
||||
tryBlock.getBlocks().addAll(innerTryBlock.getBlocks());
|
||||
@@ -188,13 +208,6 @@ public class MarkFinallyVisitor extends AbstractVisitor {
|
||||
return preds.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static void collectAllHandlers(TryCatchBlockAttr tryBlock, List<ExceptionHandler> handlers) {
|
||||
handlers.addAll(tryBlock.getHandlers());
|
||||
for (TryCatchBlockAttr innerTryBlock : tryBlock.getInnerTryBlocks()) {
|
||||
collectAllHandlers(innerTryBlock, handlers);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkSlices(FinallyExtractInfo extractInfo) {
|
||||
InsnsSlice finallySlice = extractInfo.getFinallyInsnsSlice();
|
||||
List<InsnNode> finallyInsnsList = finallySlice.getInsnsList();
|
||||
|
||||
Reference in New Issue
Block a user