📄 pass2verifier.java
字号:
CONST_InterfaceMethodref = org.apache.bcel.classfile.ConstantInterfaceMethodref.class;
*/
CONST_String = org.apache.bcel.classfile.ConstantString.class;
CONST_Integer = org.apache.bcel.classfile.ConstantInteger.class;
CONST_Float = org.apache.bcel.classfile.ConstantFloat.class;
CONST_Long = org.apache.bcel.classfile.ConstantLong.class;
CONST_Double = org.apache.bcel.classfile.ConstantDouble.class;
CONST_NameAndType = org.apache.bcel.classfile.ConstantNameAndType.class;
CONST_Utf8 = org.apache.bcel.classfile.ConstantUtf8.class;
carrier = new DescendingVisitor(_jc, this);
carrier.visit();
}
private void checkIndex(Node referrer, int index, Class shouldbe){
if ((index < 0) || (index >= cplen)){
throw new ClassConstraintException("Invalid index '"+index+"' used by '"+tostring(referrer)+"'.");
}
Constant c = cp.getConstant(index);
if (! shouldbe.isInstance(c)){
/* String isnot = shouldbe.toString().substring(shouldbe.toString().lastIndexOf(".")+1); //Cut all before last "." */
throw new ClassCastException("Illegal constant '"+tostring(c)+"' at index '"+index+"'. '"+tostring(referrer)+"' expects a '"+shouldbe+"'.");
}
}
///////////////////////////////////////
// ClassFile structure (vmspec2 4.1) //
///////////////////////////////////////
public void visitJavaClass(JavaClass obj){
Attribute[] atts = obj.getAttributes();
boolean foundSourceFile = false;
boolean foundInnerClasses = false;
// Is there an InnerClass referenced?
// This is a costly check; existing verifiers don't do it!
boolean hasInnerClass = new InnerClassDetector(jc).innerClassReferenced();
for (int i=0; i<atts.length; i++){
if ((! (atts[i] instanceof SourceFile)) &&
(! (atts[i] instanceof Deprecated)) &&
(! (atts[i] instanceof InnerClasses)) &&
(! (atts[i] instanceof Synthetic))){
addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of the ClassFile structure '"+tostring(obj)+"' is unknown and will therefore be ignored.");
}
if (atts[i] instanceof SourceFile){
if (foundSourceFile == false) foundSourceFile = true;
else throw new ClassConstraintException("A ClassFile structure (like '"+tostring(obj)+"') may have no more than one SourceFile attribute."); //vmspec2 4.7.7
}
if (atts[i] instanceof InnerClasses){
if (foundInnerClasses == false) foundInnerClasses = true;
else{
if (hasInnerClass){
throw new ClassConstraintException("A Classfile structure (like '"+tostring(obj)+"') must have exactly one InnerClasses attribute if at least one Inner Class is referenced (which is the case). More than one InnerClasses attribute was found.");
}
}
if (!hasInnerClass){
addMessage("No referenced Inner Class found, but InnerClasses attribute '"+tostring(atts[i])+"' found. Strongly suggest removal of that attribute.");
}
}
}
if (hasInnerClass && !foundInnerClasses){
//throw new ClassConstraintException("A Classfile structure (like '"+tostring(obj)+"') must have exactly one InnerClasses attribute if at least one Inner Class is referenced (which is the case). No InnerClasses attribute was found.");
//vmspec2, page 125 says it would be a constraint: but existing verifiers
//don't check it and javac doesn't satisfy it when it comes to anonymous
//inner classes
addMessage("A Classfile structure (like '"+tostring(obj)+"') must have exactly one InnerClasses attribute if at least one Inner Class is referenced (which is the case). No InnerClasses attribute was found.");
}
}
/////////////////////////////
// CONSTANTS (vmspec2 4.4) //
/////////////////////////////
public void visitConstantClass(ConstantClass obj){
if (obj.getTag() != Constants.CONSTANT_Class){
throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
}
checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
}
public void visitConstantFieldref(ConstantFieldref obj){
if (obj.getTag() != Constants.CONSTANT_Fieldref){
throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
}
checkIndex(obj, obj.getClassIndex(), CONST_Class);
checkIndex(obj, obj.getNameAndTypeIndex(), CONST_NameAndType);
}
public void visitConstantMethodref(ConstantMethodref obj){
if (obj.getTag() != Constants.CONSTANT_Methodref){
throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
}
checkIndex(obj, obj.getClassIndex(), CONST_Class);
checkIndex(obj, obj.getNameAndTypeIndex(), CONST_NameAndType);
}
public void visitConstantInterfaceMethodref(ConstantInterfaceMethodref obj){
if (obj.getTag() != Constants.CONSTANT_InterfaceMethodref){
throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
}
checkIndex(obj, obj.getClassIndex(), CONST_Class);
checkIndex(obj, obj.getNameAndTypeIndex(), CONST_NameAndType);
}
public void visitConstantString(ConstantString obj){
if (obj.getTag() != Constants.CONSTANT_String){
throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
}
checkIndex(obj, obj.getStringIndex(), CONST_Utf8);
}
public void visitConstantInteger(ConstantInteger obj){
if (obj.getTag() != Constants.CONSTANT_Integer){
throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
}
// no indices to check
}
public void visitConstantFloat(ConstantFloat obj){
if (obj.getTag() != Constants.CONSTANT_Float){
throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
}
//no indices to check
}
public void visitConstantLong(ConstantLong obj){
if (obj.getTag() != Constants.CONSTANT_Long){
throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
}
//no indices to check
}
public void visitConstantDouble(ConstantDouble obj){
if (obj.getTag() != Constants.CONSTANT_Double){
throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
}
//no indices to check
}
public void visitConstantNameAndType(ConstantNameAndType obj){
if (obj.getTag() != Constants.CONSTANT_NameAndType){
throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
}
checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
//checkIndex(obj, obj.getDescriptorIndex(), CONST_Utf8); //inconsistently named in BCEL, see below.
checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8);
}
public void visitConstantUtf8(ConstantUtf8 obj){
if (obj.getTag() != Constants.CONSTANT_Utf8){
throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
}
//no indices to check
}
//////////////////////////
// FIELDS (vmspec2 4.5) //
//////////////////////////
public void visitField(Field obj){
if (jc.isClass()){
int maxone=0;
if (obj.isPrivate()) maxone++;
if (obj.isProtected()) maxone++;
if (obj.isPublic()) maxone++;
if (maxone > 1){
throw new ClassConstraintException("Field '"+tostring(obj)+"' must only have at most one of its ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC modifiers set.");
}
if (obj.isFinal() && obj.isVolatile()){
throw new ClassConstraintException("Field '"+tostring(obj)+"' must only have at most one of its ACC_FINAL, ACC_VOLATILE modifiers set.");
}
}
else{ // isInterface!
if (!obj.isPublic()){
throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_PUBLIC modifier set but hasn't!");
}
if (!obj.isStatic()){
throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_STATIC modifier set but hasn't!");
}
if (!obj.isFinal()){
throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_FINAL modifier set but hasn't!");
}
}
if ((obj.getAccessFlags() & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_VOLATILE|ACC_TRANSIENT)) > 0){
addMessage("Field '"+tostring(obj)+"' has access flag(s) other than ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_VOLATILE, ACC_TRANSIENT set (ignored).");
}
checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
String name = obj.getName();
if (! validFieldName(name)){
throw new ClassConstraintException("Field '"+tostring(obj)+"' has illegal name '"+obj.getName()+"'.");
}
// A descriptor is often named signature in BCEL
checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8);
String sig = ((ConstantUtf8) (cp.getConstant(obj.getSignatureIndex()))).getBytes(); // Field or Method signature(=descriptor)
try{
Type.getType(sig); /* Don't need the return value */
}
catch (ClassFormatError cfe){ // sometimes BCEL is a little harsh describing exceptional situations.
throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'.");
}
String nameanddesc = (name+sig);
if (field_names_and_desc.contains(nameanddesc)){
throw new ClassConstraintException("No two fields (like '"+tostring(obj)+"') are allowed have same names and descriptors!");
}
if (field_names.contains(name)){
addMessage("More than one field of name '"+name+"' detected (but with different type descriptors). This is very unusual.");
}
field_names_and_desc.add(nameanddesc);
field_names.add(name);
Attribute[] atts = obj.getAttributes();
for (int i=0; i<atts.length; i++){
if ((! (atts[i] instanceof ConstantValue)) &&
(! (atts[i] instanceof Synthetic)) &&
(! (atts[i] instanceof Deprecated))){
addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Field '"+tostring(obj)+"' is unknown and will therefore be ignored.");
}
if (! (atts[i] instanceof ConstantValue)){
addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Field '"+tostring(obj)+"' is not a ConstantValue and is therefore only of use for debuggers and such.");
}
}
}
///////////////////////////
// METHODS (vmspec2 4.6) //
///////////////////////////
public void visitMethod(Method obj){
checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
String name = obj.getName();
if (! validMethodName(name, true)){
throw new ClassConstraintException("Method '"+tostring(obj)+"' has illegal name '"+name+"'.");
}
// A descriptor is often named signature in BCEL
checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8);
String sig = ((ConstantUtf8) (cp.getConstant(obj.getSignatureIndex()))).getBytes(); // Method's signature(=descriptor)
Type t;
Type[] ts; // needed below the try block.
try{
t = Type.getReturnType(sig);
ts = Type.getArgumentTypes(sig);
}
catch (ClassFormatError cfe){
// Well, BCEL sometimes is a little harsh describing exceptional situations.
throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by Method '"+tostring(obj)+"'.");
}
// Check if referenced objects exist.
Type act = t;
if (act instanceof ArrayType) act = ((ArrayType) act).getBasicType();
if (act instanceof ObjectType){
Verifier v = VerifierFactory.getVerifier( ((ObjectType) act).getClassName() );
VerificationResult vr = v.doPass1();
if (vr != VerificationResult.VR_OK) {
throw new ClassConstraintException("Method '"+tostring(obj)+"' has a return type that does not pass verification pass 1: '"+vr+"'.");
}
}
for (int i=0; i<ts.length; i++){
act = ts[i];
if (act instanceof ArrayType) act = ((ArrayType) act).getBasicType();
if (act instanceof ObjectType){
Verifier v = VerifierFactory.getVerifier( ((ObjectType) act).getClassName() );
VerificationResult vr = v.doPass1();
if (vr != VerificationResult.VR_OK) {
throw new ClassConstraintException("Method '"+tostring(obj)+"' has an argument type that does not pass verification pass 1: '"+vr+"'.");
}
}
}
// Nearly forgot this! Funny return values are allowed, but a non-empty arguments list makes a different method out of it!
if (name.equals(STATIC_INITIALIZER_NAME) && (ts.length != 0)){
throw new ClassConstraintException("Method '"+tostring(obj)+"' has illegal name '"+name+"'. It's name resembles the class or interface initialization method which it isn't because of its arguments (==descriptor).");
}
if (jc.isClass()){
int maxone=0;
if (obj.isPrivate()) maxone++;
if (obj.isProtected()) maxone++;
if (obj.isPublic()) maxone++;
if (maxone > 1){
throw new ClassConstraintException("Method '"+tostring(obj)+"' must only have at most one of its ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC modifiers set.");
}
if (obj.isAbstract()){
if (obj.isFinal()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_FINAL modifier set.");
if (obj.isNative()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_NATIVE modifier set.");
if (obj.isPrivate()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_PRIVATE modifier set.");
if (obj.isStatic()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_STATIC modifier set.");
if (obj.isStrictfp()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_STRICT modifier set.");
if (obj.isSynchronized()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_SYNCHRONIZED modifier set.");
}
}
else{ // isInterface!
if (!name.equals(STATIC_INITIALIZER_NAME)){//vmspec2, p.116, 2nd paragraph
if (!obj.isPublic()){
throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must have the ACC_PUBLIC modifier set but hasn't!");
}
if (!obj.isAbstract()){
throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must have the ACC_STATIC modifier set but hasn't!");
}
if ( obj.isPrivate() ||
obj.isProtected() ||
obj.isStatic() ||
obj.isFinal() ||
obj.isSynchronized() ||
obj.isNative() ||
obj.isStrictfp() ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -