in src/main/java/org/apache/bcel/verifier/statics/Pass3aVerifier.java [904:990]
private void delayedPass2Checks() {
final int[] instructionPositions = instructionList.getInstructionPositions();
final int codeLength = code.getCode().length;
/////////////////////
// LineNumberTable //
/////////////////////
final LineNumberTable lnt = code.getLineNumberTable();
if (lnt != null) {
final LineNumber[] lineNumbers = lnt.getLineNumberTable();
final IntList offsets = new IntList();
lineNumberLoop: for (final LineNumber lineNumber : lineNumbers) { // may appear in any order.
for (final int instructionPosition : instructionPositions) {
// TODO: Make this a binary search! The instructionPositions array is naturally ordered!
final int offset = lineNumber.getStartPC();
if (instructionPosition == offset) {
if (offsets.contains(offset)) {
addMessage("LineNumberTable attribute '" + code.getLineNumberTable() + "' refers to the same code offset ('" + offset
+ "') more than once" + " which is violating the semantics [but is sometimes produced by IBM's 'jikes' compiler].");
} else {
offsets.add(offset);
}
continue lineNumberLoop;
}
}
throw new ClassConstraintException("Code attribute '" + tostring(code) + "' has a LineNumberTable attribute '" + code.getLineNumberTable()
+ "' referring to a code offset ('" + lineNumber.getStartPC() + "') that does not exist.");
}
}
///////////////////////////
// LocalVariableTable(s) //
///////////////////////////
/*
* We cannot use code.getLocalVariableTable() because there could be more than only one. This is a bug in BCEL.
*/
final Attribute[] atts = code.getAttributes();
for (final Attribute att : atts) {
if (att instanceof LocalVariableTable) {
((LocalVariableTable) att).forEach(localVariable -> {
final int startpc = localVariable.getStartPC();
final int length = localVariable.getLength();
if (!contains(instructionPositions, startpc)) {
throw new ClassConstraintException("Code attribute '" + tostring(code) + "' has a LocalVariableTable attribute '"
+ code.getLocalVariableTable() + "' referring to a code offset ('" + startpc + "') that does not exist.");
}
if (!contains(instructionPositions, startpc + length) && startpc + length != codeLength) {
throw new ClassConstraintException(
"Code attribute '" + tostring(code) + "' has a LocalVariableTable attribute '" + code.getLocalVariableTable()
+ "' referring to a code offset start_pc+length ('" + (startpc + length) + "') that does not exist.");
}
});
}
}
////////////////////
// ExceptionTable //
////////////////////
// In BCEL's "classfile" API, the startPC/endPC-notation is
// inclusive/exclusive as in the Java Virtual Machine Specification.
// WARNING: This is not true for BCEL's "generic" API.
final CodeException[] exceptionTable = code.getExceptionTable();
for (final CodeException element : exceptionTable) {
final int startpc = element.getStartPC();
final int endpc = element.getEndPC();
final int handlerpc = element.getHandlerPC();
if (startpc >= endpc) {
throw new ClassConstraintException("Code attribute '" + tostring(code) + "' has an exception_table entry '" + element
+ "' that has its start_pc ('" + startpc + "') not smaller than its end_pc ('" + endpc + "').");
}
if (!contains(instructionPositions, startpc)) {
throw new ClassConstraintException("Code attribute '" + tostring(code) + "' has an exception_table entry '" + element
+ "' that has a non-existant bytecode offset as its start_pc ('" + startpc + "').");
}
if (!contains(instructionPositions, endpc) && endpc != codeLength) {
throw new ClassConstraintException("Code attribute '" + tostring(code) + "' has an exception_table entry '" + element
+ "' that has a non-existant bytecode offset as its end_pc ('" + startpc + "') [that is also not equal to code_length ('" + codeLength
+ "')].");
}
if (!contains(instructionPositions, handlerpc)) {
throw new ClassConstraintException("Code attribute '" + tostring(code) + "' has an exception_table entry '" + element
+ "' that has a non-existant bytecode offset as its handler_pc ('" + handlerpc + "').");
}
}
}