in src/main/java/org/apache/bcel/verifier/statics/Pass3aVerifier.java [434:502]
public void visitInvokeInstruction(final InvokeInstruction o) {
indexValid(o, o.getIndex());
if (o instanceof INVOKEVIRTUAL || o instanceof INVOKESPECIAL || o instanceof INVOKESTATIC) {
final Constant c = constantPoolGen.getConstant(o.getIndex());
if (!(c instanceof ConstantMethodref)) {
constraintViolated(o, "Indexing a constant that's not a CONSTANT_Methodref but a '" + tostring(c) + "'.");
} else {
// Constants are okay due to pass2.
final ConstantNameAndType cnat = (ConstantNameAndType) constantPoolGen.getConstant(((ConstantMethodref) c).getNameAndTypeIndex());
final ConstantUtf8 cutf8 = (ConstantUtf8) constantPoolGen.getConstant(cnat.getNameIndex());
if (cutf8.getBytes().equals(Const.CONSTRUCTOR_NAME) && !(o instanceof INVOKESPECIAL)) {
constraintViolated(o, "Only INVOKESPECIAL is allowed to invoke instance initialization methods.");
}
if (!cutf8.getBytes().equals(Const.CONSTRUCTOR_NAME) && cutf8.getBytes().startsWith("<")) {
constraintViolated(o, "No method with a name beginning with '<' other than the instance initialization methods"
+ " may be called by the method invocation instructions.");
}
}
} else {
final Constant c = constantPoolGen.getConstant(o.getIndex());
if (!(c instanceof ConstantInterfaceMethodref) && !(c instanceof ConstantInvokeDynamic)) {
constraintViolated(o, "Indexing a constant that's not a CONSTANT_InterfaceMethodref/InvokeDynamic but a '" + tostring(c) + "'.");
}
// TODO: From time to time check if BCEL allows to detect if the
// 'count' operand is consistent with the information in the
// CONSTANT_InterfaceMethodref and if the last operand is zero.
// By now, BCEL hides those two operands because they're superfluous.
// Invoked method must not be <init> or <clinit>
final ConstantNameAndType cnat = (ConstantNameAndType) constantPoolGen.getConstant(((ConstantCP) c).getNameAndTypeIndex());
final String name = ((ConstantUtf8) constantPoolGen.getConstant(cnat.getNameIndex())).getBytes();
if (name.equals(Const.CONSTRUCTOR_NAME)) {
constraintViolated(o, "Method to invoke must not be '" + Const.CONSTRUCTOR_NAME + "'.");
}
if (name.equals(Const.STATIC_INITIALIZER_NAME)) {
constraintViolated(o, "Method to invoke must not be '" + Const.STATIC_INITIALIZER_NAME + "'.");
}
}
// The LoadClassType is the method-declaring class, so we have to check the other types.
Type t = o.getReturnType(constantPoolGen);
if (t instanceof ArrayType) {
t = ((ArrayType) t).getBasicType();
}
if (t instanceof ObjectType) {
final Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName());
final VerificationResult vr = v.doPass2();
if (vr.getStatus() != VerificationResult.VERIFIED_OK) {
constraintViolated(o, "Return type class/interface could not be verified successfully: '" + vr.getMessage() + "'.");
}
}
final Type[] ts = o.getArgumentTypes(constantPoolGen);
for (final Type element : ts) {
t = element;
if (t instanceof ArrayType) {
t = ((ArrayType) t).getBasicType();
}
if (t instanceof ObjectType) {
final Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName());
final VerificationResult vr = v.doPass2();
if (vr.getStatus() != VerificationResult.VERIFIED_OK) {
constraintViolated(o, "Argument type class/interface could not be verified successfully: '" + vr.getMessage() + "'.");
}
}
}
}