Code with Finding: |
class InstConstraintVisitor {
/**
* Ensures the specific preconditions of the said instruction.
*/
@Override
public void visitINVOKESPECIAL(INVOKESPECIAL o){
try {
// Don't init an object twice.
if ( (o.getMethodName(cpg).equals(Const.CONSTRUCTOR_NAME)) &&
(!(stack().peek(o.getArgumentTypes(cpg).length) instanceof UninitializedObjectType)) ){
constraintViolated(o, "Possibly initializing object twice."+
" A valid instruction sequence must not have an uninitialized object on the operand stack or in a local variable"+
" during a backwards branch, or in a local variable in code protected by an exception handler."+
" Please see The Java Virtual Machine Specification, Second Edition, 4.9.4 (pages 147 and 148) for details.");
}
// the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).
Type t = o.getType(cpg);
if (t instanceof ObjectType){
String name = ((ObjectType)t).getClassName();
Verifier v = VerifierFactory.getVerifier( name );
VerificationResult vr = v.doPass2();
if (vr.getStatus() != VerificationResult.VERIFIED_OK){
constraintViolated(o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
}
}
Type[] argtypes = o.getArgumentTypes(cpg);
int nargs = argtypes.length;
for (int i=nargs-1; i>=0; i--){
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){
ReferenceType rFromStack = (ReferenceType) fromStack;
ReferenceType rFromDesc = (ReferenceType) fromDesc;
// TODO: This can only be checked using Staerk-et-al's "set of object types", not
// using a "wider cast object type".
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+"'.");
}
String objref_classname = null;
if ( !(o.getMethodName(cpg).equals(Const.CONSTRUCTOR_NAME))){
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;
}
}
objref_classname = ((ObjectType) objref).getClassName();
}
else{
if (!(objref instanceof UninitializedObjectType)){
constraintViolated(o, "Expecting an UninitializedObjectType as 'objectref' on the stack, not a '"+objref+
"'. Otherwise, you couldn't invoke a method since an array has no methods (not to speak of a return address).");
}
objref_classname = ((UninitializedObjectType) objref).getInitialized().getClassName();
}
String theClass = o.getClassName(cpg);
if ( ! Repository.instanceOf(objref_classname, theClass) ){
constraintViolated(o, "The 'objref' item '"+objref+"' does not implement '"+theClass+"' as expected.");
}
} catch (ClassNotFoundException e) {
// FIXME: maybe not the best way to handle this
throw new AssertionViolatedException("Missing class: " + e, e);
}
}
}
|