Methods Summary |
---|
private void | constant_pool_entries_satisfy_static_constraints()Ensures that the constant pool entries satisfy the static constraints
as described in The Java Virtual Machine Specification, 2nd Edition.
// Most of the consistency is handled internally by BCEL; here
// we only have to verify if the indices of the constants point
// to constants of the appropriate type and such.
JavaClass jc = Repository.lookupClass(myOwner.getClassName());
new CPESSC_Visitor(jc); // constructor implicitely traverses jc
|
public VerificationResult | do_verify()Pass 2 is the pass where static properties of the
class file are checked without looking into "Code"
arrays of methods.
This verification pass is usually invoked when
a class is resolved; and it may be possible that
this verification pass has to load in other classes
such as superclasses or implemented interfaces.
Therefore, Pass 1 is run on them.
Note that most referenced classes are not loaded
in for verification or for an existance check by this
pass; only the syntactical correctness of their names
and descriptors (a.k.a. signatures) is checked.
Very few checks that conceptually belong here
are delayed until pass 3a in JustIce. JustIce does
not only check for syntactical correctness but also
for semantical sanity - therefore it needs access to
the "Code" array of methods in a few cases. Please
see the pass 3a documentation, too.
VerificationResult vr1 = myOwner.doPass1();
if (vr1.equals(VerificationResult.VR_OK)){
// For every method, we could have information about the local variables out of LocalVariableTable attributes of
// the Code attributes.
localVariablesInfos = new LocalVariablesInfo[Repository.lookupClass(myOwner.getClassName()).getMethods().length];
VerificationResult vr = VerificationResult.VR_OK; // default.
try{
constant_pool_entries_satisfy_static_constraints();
field_and_method_refs_are_valid();
every_class_has_an_accessible_superclass();
final_methods_are_not_overridden();
}
catch (ClassConstraintException cce){
vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, cce.getMessage());
}
return vr;
}
else
return VerificationResult.VR_NOTYET;
|
private void | every_class_has_an_accessible_superclass()Ensures that every class has a super class and that
final classes are not subclassed.
This means, the class this Pass2Verifier operates
on has proper super classes (transitively) up to
java.lang.Object.
The reason for really loading (and Pass1-verifying)
all of those classes here is that we need them in
Pass2 anyway to verify no final methods are overridden
(that could be declared anywhere in the ancestor hierarchy).
HashSet hs = new HashSet(); // save class names to detect circular inheritance
JavaClass jc = Repository.lookupClass(myOwner.getClassName());
int supidx = -1;
while (supidx != 0){
supidx = jc.getSuperclassNameIndex();
if (supidx == 0){
if (jc != Repository.lookupClass(Type.OBJECT.getClassName())){
throw new ClassConstraintException("Superclass of '"+jc.getClassName()+"' missing but not "+Type.OBJECT.getClassName()+" itself!");
}
}
else{
String supername = jc.getSuperclassName();
if (! hs.add(supername)){ // If supername already is in the list
throw new ClassConstraintException("Circular superclass hierarchy detected.");
}
Verifier v = VerifierFactory.getVerifier(supername);
VerificationResult vr = v.doPass1();
if (vr != VerificationResult.VR_OK){
throw new ClassConstraintException("Could not load in ancestor class '"+supername+"'.");
}
jc = Repository.lookupClass(supername);
if (jc.isFinal()){
throw new ClassConstraintException("Ancestor class '"+supername+"' has the FINAL access modifier and must therefore not be subclassed.");
}
}
}
|
private void | field_and_method_refs_are_valid()Ensures that the ConstantCP-subclassed entries of the constant
pool are valid. According to "Yellin: Low Level Security in Java",
this method does not verify the existence of referenced entities
(such as classes) but only the formal correctness (such as well-formed
signatures).
The visitXXX() methods throw ClassConstraintException instances otherwise.
Precondition: index-style cross referencing in the constant
pool must be valid. Simply invoke constant_pool_entries_satisfy_static_constraints()
before.
JavaClass jc = Repository.lookupClass(myOwner.getClassName());
DescendingVisitor v = new DescendingVisitor(jc, new FAMRAV_Visitor(jc));
v.visit();
|
private void | final_methods_are_not_overridden()Ensures that final methods are not overridden.
Precondition to run this method:
constant_pool_entries_satisfy_static_constraints() and
every_class_has_an_accessible_superclass() have to be invoked before
(in that order).
HashMap hashmap = new HashMap();
JavaClass jc = Repository.lookupClass(myOwner.getClassName());
int supidx = -1;
while (supidx != 0){
supidx = jc.getSuperclassNameIndex();
ConstantPoolGen cpg = new ConstantPoolGen(jc.getConstantPool());
Method[] methods = jc.getMethods();
for (int i=0; i<methods.length; i++){
String name_and_sig = (methods[i].getName()+methods[i].getSignature());
if (hashmap.containsKey(name_and_sig)){
if (methods[i].isFinal()){
throw new ClassConstraintException("Method '"+name_and_sig+"' in class '"+hashmap.get(name_and_sig)+"' overrides the final (not-overridable) definition in class '"+jc.getClassName()+"'.");
}
else{
if (!methods[i].isStatic()){ // static methods don't inherit
hashmap.put(name_and_sig, jc.getClassName());
}
}
}
else{
if (!methods[i].isStatic()){ // static methods don't inherit
hashmap.put(name_and_sig, jc.getClassName());
}
}
}
jc = Repository.lookupClass(jc.getSuperclassName()); // Well, for OBJECT this returns OBJECT so it works (could return anything but must not throw an Exception).
}
|
public LocalVariablesInfo | getLocalVariablesInfo(int method_nr)Returns a LocalVariablesInfo object containing information
about the usage of the local variables in the Code attribute
of the said method or null if the class file this
Pass2Verifier operates on could not be pass-2-verified correctly.
The method number method_nr is the method you get using
Repository.lookupClass(myOwner.getClassname()).getMethods()[method_nr];.
You should not add own information. Leave that to JustIce.
if (this.verify() != VerificationResult.VR_OK) return null; // It's cached, don't worry.
if (method_nr < 0 || method_nr >= localVariablesInfos.length){
throw new AssertionViolatedException("Method number out of range.");
}
return localVariablesInfos[method_nr];
|
private static java.lang.String | tostring(com.sun.org.apache.bcel.internal.classfile.Node n)This method is here to save typing work and improve code readability.
return new StringRepresentation(n).toString();
|
private static boolean | validClassMethodName(java.lang.String name)This method returns true if and only if the supplied String
represents a valid method name that may be referenced by
ConstantMethodref objects.
return validMethodName(name, false);
|
private static final boolean | validClassName(java.lang.String name)This method returns true if and only if the supplied String
represents a valid Java class name.
// Are there restrictions?
return true;
|
private static boolean | validFieldName(java.lang.String name)This method returns true if and only if the supplied String
represents a valid Java field name.
// vmspec2 2.7, vmspec2 2.2
return validJavaIdentifier(name);
|
private static boolean | validInterfaceMethodName(java.lang.String name)This method returns true if and only if the supplied String
represents a valid Java interface method name that may be
referenced by ConstantInterfaceMethodref objects.
// I guess we should assume special names forbidden here.
if (name.startsWith("<")) return false;
return validJavaLangMethodName(name);
|
private static boolean | validJavaIdentifier(java.lang.String name)This method returns true if and only if the supplied String
represents a valid Java identifier (so-called simple name).
// vmspec2 2.7, vmspec2 2.2
if (!Character.isJavaIdentifierStart(name.charAt(0))) return false;
for (int i=1; i<name.length(); i++){
if (!Character.isJavaIdentifierPart(name.charAt(i))) return false;
}
return true;
|
private static boolean | validJavaLangMethodName(java.lang.String name)This method returns true if and only if the supplied String
represents a valid Java programming language method name stored as a simple
(non-qualified) name.
Conforming to: The Java Virtual Machine Specification, Second Edition, ÷2.7, ÷2.7.1, ÷2.2.
if (!Character.isJavaIdentifierStart(name.charAt(0))) return false;
for (int i=1; i<name.length(); i++){
if (!Character.isJavaIdentifierPart(name.charAt(i))) return false;
}
return true;
|
private static boolean | validMethodName(java.lang.String name, boolean allowStaticInit)This method returns true if and only if the supplied String
represents a valid method name.
This is basically the same as a valid identifier name in the
Java programming language, but the special name for
the instance initialization method is allowed and the special name
for the class/interface initialization method may be allowed.
if (validJavaLangMethodName(name)) return true;
if (allowStaticInit){
return (name.equals(CONSTRUCTOR_NAME) || name.equals(STATIC_INITIALIZER_NAME));
}
else{
return name.equals(CONSTRUCTOR_NAME);
}
|