in src/main/java/org/apache/bcel/verifier/structurals/InstConstraintVisitor.java [1553:1633]
public void visitINVOKEINTERFACE(final INVOKEINTERFACE o) {
// Method is not native, otherwise pass 3 would not happen.
final int count = o.getCount();
if (count == 0) {
constraintViolated(o, "The 'count' argument must not be 0.");
}
// It is a ConstantInterfaceMethodref, Pass 3a made it sure.
// TODO: Do we want to do anything with it?
// ConstantInterfaceMethodref cimr = (ConstantInterfaceMethodref) (cpg.getConstant(o.getIndex()));
// the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).
final Type t = o.getType(cpg);
if (t instanceof ObjectType) {
final String name = ((ObjectType) t).getClassName();
final Verifier v = VerifierFactory.getVerifier(name);
final VerificationResult vr = v.doPass2();
if (vr.getStatus() != VerificationResult.VERIFIED_OK) {
constraintViolated(o, "Class '" + name + "' is referenced, but cannot be loaded and resolved: '" + vr + "'.");
}
}
final Type[] argtypes = o.getArgumentTypes(cpg);
final int nargs = argtypes.length;
for (int i = nargs - 1; i >= 0; i--) {
final Type fromStack = stack().peek(nargs - 1 - i); // 0 to nargs-1
Type fromDesc = argtypes[i];
if (fromDesc == Type.BOOLEAN || fromDesc == Type.BYTE || fromDesc == Type.CHAR || fromDesc == Type.SHORT) {
fromDesc = Type.INT;
}
if (!fromStack.equals(fromDesc)) {
if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType) {
final ReferenceType rFromStack = (ReferenceType) fromStack;
// ReferenceType rFromDesc = (ReferenceType) fromDesc;
// TODO: This can only be checked when using Staerk-et-al's "set of object types"
// instead of a "wider cast object type" created during verification.
// if ( ! rFromStack.isAssignmentCompatibleWith(rFromDesc) ) {
// constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+
// "' on the stack (which is not assignment compatible).");
// }
referenceTypeIsInitialized(o, rFromStack);
} else {
constraintViolated(o, "Expecting a '" + fromDesc + "' but found a '" + fromStack + "' on the stack.");
}
}
}
Type objref = stack().peek(nargs);
if (objref == Type.NULL) {
return;
}
if (!(objref instanceof ReferenceType)) {
constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '" + objref + "'.");
}
referenceTypeIsInitialized(o, (ReferenceType) objref);
if (!(objref instanceof ObjectType)) {
if (!(objref instanceof ArrayType)) { // could be a ReturnaddressType
constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '" + objref + "'.");
} else {
objref = GENERIC_ARRAY;
}
}
// String objref_classname = ((ObjectType) objref).getClassName();
// String theInterface = o.getClassName(cpg);
// TODO: This can only be checked if we're using Staerk-et-al's "set of object types"
// instead of "wider cast object types" generated during verification.
// if ( ! Repository.implementationOf(objref_classname, theInterface) ) {
// constraintViolated(o, "The 'objref' item '"+objref+"' does not implement '"+theInterface+"' as expected.");
// }
int countedCount = 1; // 1 for the objectref
for (int i = 0; i < nargs; i++) {
countedCount += argtypes[i].getSize();
}
if (count != countedCount) {
constraintViolated(o, "The 'count' argument should probably read '" + countedCount + "' but is '" + count + "'.");
}
}