checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes();
if (! name.equals("Code")){
throw new ClassConstraintException("The Code attribute '"+tostring(obj)+"' is not correctly named 'Code' but '"+name+"'.");
}
Method m = null; // satisfy compiler
if (!(carrier.predecessor() instanceof Method)){
addMessage("Code attribute '"+tostring(obj)+"' is not declared in a method_info structure but in '"+carrier.predecessor()+"'. Ignored.");
return;
}
else{
m = (Method) carrier.predecessor(); // we can assume this method was visited before;
// i.e. the data consistency was verified.
}
if (obj.getCode().length == 0){
throw new ClassConstraintException("Code array of Code attribute '"+tostring(obj)+"' (method '"+m+"') must not be empty.");
}
//In JustIce, the check for correct offsets into the code array is delayed to Pass 3a.
CodeException[] exc_table = obj.getExceptionTable();
for (int i=0; i<exc_table.length; i++){
int exc_index = exc_table[i].getCatchType();
if (exc_index != 0){ // if 0, it catches all Throwables
checkIndex(obj, exc_index, CONST_Class);
ConstantClass cc = (ConstantClass) (cp.getConstant(exc_index));
checkIndex(cc, cc.getNameIndex(), CONST_Utf8); // cannot be sure this ConstantClass has already been visited (checked)!
String cname = ((ConstantUtf8) cp.getConstant(cc.getNameIndex())).getBytes().replace('/','.');
Verifier v = VerifierFactory.getVerifier(cname);
VerificationResult vr = v.doPass1();
if (vr != VerificationResult.VR_OK){
throw new ClassConstraintException("Code attribute '"+tostring(obj)+"' (method '"+m+"') has an exception_table entry '"+tostring(exc_table[i])+"' that references '"+cname+"' as an Exception but it does not pass verification pass 1: "+vr);
}
else{
// We cannot safely trust any other "instanceof" mechanism. We need to transitively verify
// the ancestor hierarchy.
JavaClass e = Repository.lookupClass(cname);
JavaClass t = Repository.lookupClass(Type.THROWABLE.getClassName());
JavaClass o = Repository.lookupClass(Type.OBJECT.getClassName());
while (e != o){
if (e == t) break; // It's a subclass of Throwable, OKAY, leave.
v = VerifierFactory.getVerifier(e.getSuperclassName());
vr = v.doPass1();
if (vr != VerificationResult.VR_OK){
throw new ClassConstraintException("Code attribute '"+tostring(obj)+"' (method '"+m+"') has an exception_table entry '"+tostring(exc_table[i])+"' that references '"+cname+"' as an Exception but '"+e.getSuperclassName()+"' in the ancestor hierachy does not pass verification pass 1: "+vr);
}
else{
e = Repository.lookupClass(e.getSuperclassName());
}
}
if (e != t) throw new ClassConstraintException("Code attribute '"+tostring(obj)+"' (method '"+m+"') has an exception_table entry '"+tostring(exc_table[i])+"' that references '"+cname+"' as an Exception but it is not a subclass of '"+t.getClassName()+"'.");
}
}
}
// Create object for local variables information
// This is highly unelegant due to usage of the Visitor pattern.
// TODO: rework it.
int method_number = -1;
Method[] ms = Repository.lookupClass(myOwner.getClassName()).getMethods();
for (int mn=0; mn<ms.length; mn++){
if (m == ms[mn]){
method_number = mn;
break;
}
}
if (method_number < 0){ // Mmmmh. Can we be sure BCEL does not sometimes instantiate new objects?
throw new AssertionViolatedException("Could not find a known BCEL Method object in the corresponding BCEL JavaClass object.");
}
localVariablesInfos[method_number] = new LocalVariablesInfo(obj.getMaxLocals());
int num_of_lvt_attribs = 0;
// Now iterate through the attributes the Code attribute has.
Attribute[] atts = obj.getAttributes();
for (int a=0; a<atts.length; a++){
if ((! (atts[a] instanceof LineNumberTable)) &&
(! (atts[a] instanceof LocalVariableTable))){
addMessage("Attribute '"+tostring(atts[a])+"' as an attribute of Code attribute '"+tostring(obj)+"' (method '"+m+"') is unknown and will therefore be ignored.");
}
else{// LineNumberTable or LocalVariableTable
addMessage("Attribute '"+tostring(atts[a])+"' as an attribute of Code attribute '"+tostring(obj)+"' (method '"+m+"') will effectively be ignored and is only useful for debuggers and such.");
}
//LocalVariableTable check (partially delayed to Pass3a).
//Here because its easier to collect the information of the
//(possibly more than one) LocalVariableTables belonging to
//one certain Code attribute.
if (atts[a] instanceof LocalVariableTable){ // checks conforming to vmspec2 4.7.9
LocalVariableTable lvt = (LocalVariableTable) atts[a];
checkIndex(lvt, lvt.getNameIndex(), CONST_Utf8);
String lvtname = ((ConstantUtf8) cp.getConstant(lvt.getNameIndex())).getBytes();
if (! lvtname.equals("LocalVariableTable")){
throw new ClassConstraintException("The LocalVariableTable attribute '"+tostring(lvt)+"' is not correctly named 'LocalVariableTable' but '"+lvtname+"'.");
}
Code code = obj;
//In JustIce, the check for correct offsets into the code array is delayed to Pass 3a.
LocalVariable[] localvariables = lvt.getLocalVariableTable();
for (int i=0; i<localvariables.length; i++){
checkIndex(lvt, localvariables[i].getNameIndex(), CONST_Utf8);
String localname = ((ConstantUtf8) cp.getConstant(localvariables[i].getNameIndex())).getBytes();
if (!validJavaIdentifier(localname)){
throw new ClassConstraintException("LocalVariableTable '"+tostring(lvt)+"' references a local variable by the name '"+localname+"' which is not a legal Java simple name.");
}
checkIndex(lvt, localvariables[i].getSignatureIndex(), CONST_Utf8);
String localsig = ((ConstantUtf8) (cp.getConstant(localvariables[i].getSignatureIndex()))).getBytes(); // Local signature(=descriptor)
Type t;
try{
t = Type.getType(localsig);
}
catch (ClassFormatError cfe){ // sometimes BCEL is a little harsh describing exceptional situations.
throw new ClassConstraintException("Illegal descriptor (==signature) '"+localsig+"' used by LocalVariable '"+tostring(localvariables[i])+"' referenced by '"+tostring(lvt)+"'.");
}
int localindex = localvariables[i].getIndex();
if ( ( (t==Type.LONG || t==Type.DOUBLE)? localindex+1:localindex) >= code.getMaxLocals()){
throw new ClassConstraintException("LocalVariableTable attribute '"+tostring(lvt)+"' references a LocalVariable '"+tostring(localvariables[i])+"' with an index that exceeds the surrounding Code attribute's max_locals value of '"+code.getMaxLocals()+"'.");
}
try{
localVariablesInfos[method_number].add(localindex, localname, localvariables[i].getStartPC(), localvariables[i].getLength(), t);
}
catch(LocalVariableInfoInconsistentException lviie){
throw new ClassConstraintException("Conflicting information in LocalVariableTable '"+tostring(lvt)+"' found in Code attribute '"+tostring(obj)+"' (method '"+tostring(m)+"'). "+lviie.getMessage());
}
}// for all local variables localvariables[i] in the LocalVariableTable attribute atts[a] END
num_of_lvt_attribs++;
if (num_of_lvt_attribs > obj.getMaxLocals()){
throw new ClassConstraintException("Number of LocalVariableTable attributes of Code attribute '"+tostring(obj)+"' (method '"+tostring(m)+"') exceeds number of local variable slots '"+obj.getMaxLocals()+"' ('There may be no more than one LocalVariableTable attribute per local variable in the Code attribute.').");
}
}// if atts[a] instanceof LocalVariableTable END
}// for all attributes atts[a] END
}// visitCode(Code) END