Commit cfbfe492 authored by Eric Bruneton's avatar Eric Bruneton

Merge branch '317851-fix-analyzer-stack-overflow' into 'master'

Resolve "Analyzer gets StackOverflowError when method has lots of jumps"

Closes #317851

See merge request !204
parents f52a21ff 77de867c
Pipeline #2733 passed with stage
in 7 minutes and 23 seconds
......@@ -305,52 +305,55 @@ public class Analyzer<V extends Value> implements Opcodes {
private void findSubroutine(
final int insnIndex, final Subroutine subroutine, final List<AbstractInsnNode> jsrInsns)
throws AnalyzerException {
int currentInsnIndex = insnIndex;
while (true) {
ArrayList<Integer> instructionIndicesToProcess = new ArrayList<Integer>();
instructionIndicesToProcess.add(insnIndex);
while (!instructionIndicesToProcess.isEmpty()) {
int currentInsnIndex =
instructionIndicesToProcess.remove(instructionIndicesToProcess.size() - 1);
if (currentInsnIndex < 0 || currentInsnIndex >= insnListSize) {
throw new AnalyzerException(null, "Execution can fall off the end of the code");
}
if (subroutines[currentInsnIndex] != null) {
return;
continue;
}
subroutines[currentInsnIndex] = new Subroutine(subroutine);
AbstractInsnNode currentInsn = insnList.get(currentInsnIndex);
// Call findSubroutine recursively on the normal successors of currentInsn.
// Push the normal successors of currentInsn onto instructionIndicesToProcess.
if (currentInsn instanceof JumpInsnNode) {
if (currentInsn.getOpcode() == JSR) {
// Do not follow a jsr, it leads to another subroutine!
jsrInsns.add(currentInsn);
} else {
JumpInsnNode jumpInsn = (JumpInsnNode) currentInsn;
findSubroutine(insnList.indexOf(jumpInsn.label), subroutine, jsrInsns);
instructionIndicesToProcess.add(insnList.indexOf(jumpInsn.label));
}
} else if (currentInsn instanceof TableSwitchInsnNode) {
TableSwitchInsnNode tableSwitchInsn = (TableSwitchInsnNode) currentInsn;
findSubroutine(insnList.indexOf(tableSwitchInsn.dflt), subroutine, jsrInsns);
for (int i = tableSwitchInsn.labels.size() - 1; i >= 0; --i) {
LabelNode l = tableSwitchInsn.labels.get(i);
findSubroutine(insnList.indexOf(l), subroutine, jsrInsns);
LabelNode labelNode = tableSwitchInsn.labels.get(i);
instructionIndicesToProcess.add(insnList.indexOf(labelNode));
}
} else if (currentInsn instanceof LookupSwitchInsnNode) {
LookupSwitchInsnNode lookupSwitchInsn = (LookupSwitchInsnNode) currentInsn;
findSubroutine(insnList.indexOf(lookupSwitchInsn.dflt), subroutine, jsrInsns);
for (int i = lookupSwitchInsn.labels.size() - 1; i >= 0; --i) {
LabelNode l = lookupSwitchInsn.labels.get(i);
findSubroutine(insnList.indexOf(l), subroutine, jsrInsns);
LabelNode labelNode = lookupSwitchInsn.labels.get(i);
instructionIndicesToProcess.add(insnList.indexOf(labelNode));
}
}
// Call findSubroutine recursively on the exception handler successors of currentInsn.
// Push the exception handler successors of currentInsn onto instructionIndicesToProcess.
List<TryCatchBlockNode> insnHandlers = handlers[currentInsnIndex];
if (insnHandlers != null) {
for (int i = 0; i < insnHandlers.size(); ++i) {
TryCatchBlockNode tryCatchBlock = insnHandlers.get(i);
findSubroutine(insnList.indexOf(tryCatchBlock.handler), subroutine, jsrInsns);
instructionIndicesToProcess.add(insnList.indexOf(tryCatchBlock.handler));
}
}
// If currentInsn does not fall through to the next instruction, return.
// Push the next instruction, if the control flow can go from currentInsn to the next.
switch (currentInsn.getOpcode()) {
case GOTO:
case RET:
......@@ -363,11 +366,11 @@ public class Analyzer<V extends Value> implements Opcodes {
case ARETURN:
case RETURN:
case ATHROW:
return;
break;
default:
instructionIndicesToProcess.add(currentInsnIndex + 1);
break;
}
currentInsnIndex++;
}
}
......
......@@ -820,6 +820,21 @@ public class AnalyzerTest {
assertMaxs(4, 6);
}
/** Tests that Analyzer works correctly on classes with many labels. */
@Test
public void testManyLabels() {
Label target = new Label();
JSR(target);
LABEL(target);
for (int i = 0; i < 8192; i++) {
Label label = new Label();
GOTO(label);
LABEL(label);
}
RETURN();
assertMaxs(1, 1);
}
/**
* Tests an example coming from distilled down version of
* com/sun/corba/ee/impl/protocol/CorbaClientDelegateImpl from GlassFish 2. See issue #317823.
......@@ -911,9 +926,9 @@ public class AnalyzerTest {
return new MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) {
@Override
public void visitEnd() {
Analyzer<BasicValue> a = new Analyzer<BasicValue>(new BasicInterpreter());
Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(new BasicInterpreter());
try {
Frame<BasicValue>[] frames = a.analyze("C", this);
Frame<BasicValue>[] frames = analyzer.analyze("C", this);
int mStack = 0;
int mLocals = 0;
for (int i = 0; i < frames.length; ++i) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment