public void visitCode()

in src/main/java/org/apache/bcel/verifier/statics/Pass2Verifier.java [155:326]


        public void visitCode(final Code obj) { // vmspec2 4.7.3
            try {
                // No code attribute allowed for native or abstract methods: see visitMethod(Method).
                // Code array constraints are checked in Pass3 (3a and 3b).

                checkIndex(obj, obj.getNameIndex(), CONST_Utf8);

                final 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 + "'.");
                }

                if (!(carrier.predecessor() instanceof Method)) {
                    addMessage("Code attribute '" + tostring(obj) + "' is not declared in a method_info structure but in '" + carrier.predecessor()
                            + "'. Ignored.");
                    return;
                }
                final Method 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.
                final CodeException[] excTable = obj.getExceptionTable();
                for (final CodeException element : excTable) {
                    final int excIndex = element.getCatchType();
                    if (excIndex != 0) { // if 0, it catches all Throwables
                        checkIndex(obj, excIndex, CONST_Class);
                        final ConstantClass cc = (ConstantClass) cp.getConstant(excIndex);
                        // cannot be sure this ConstantClass has already been visited (checked)!
                        checkIndex(cc, cc.getNameIndex(), CONST_Utf8);
                        final String cname = Utility.pathToPackage(((ConstantUtf8) cp.getConstant(cc.getNameIndex())).getBytes());

                        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(element) + "' that references '" + cname + "' as an Exception but it does not pass verification pass 1: " + vr);
                        }
                        // We cannot safely trust any other "instanceof" mechanism. We need to transitively verify
                        // the ancestor hierarchy.
                        JavaClass e = Repository.lookupClass(cname);
                        final JavaClass t = Repository.lookupClass(Type.THROWABLE.getClassName());
                        final 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(element) + "' that references '" + cname + "' as an Exception but '" + e.getSuperclassName()
                                        + "' in the ancestor hierachy does not pass verification pass 1: " + vr);
                            }
                            e = Repository.lookupClass(e.getSuperclassName());
                        }
                        if (e != t) {
                            throw new ClassConstraintException(
                                    "Code attribute '" + tostring(obj) + "' (method '" + m + "') has an exception_table entry '" + tostring(element)
                                            + "' 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 methodNumber = -1;
                final Method[] ms = Repository.lookupClass(verifier.getClassName()).getMethods();
                for (int mn = 0; mn < ms.length; mn++) {
                    if (m == ms[mn]) {
                        methodNumber = mn;
                        break;
                    }
                }
                // If the .class file is malformed the loop above may not find a method.
                // Try matching names instead of pointers.
                if (methodNumber < 0) {
                    for (int mn = 0; mn < ms.length; mn++) {
                        if (m.getName().equals(ms[mn].getName())) {
                            methodNumber = mn;
                            break;
                        }
                    }
                }

                if (methodNumber < 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[methodNumber] = new LocalVariablesInfo(obj.getMaxLocals());

                int numOfLvtAttribs = 0;
                // Now iterate through the attributes the Code attribute has.
                final Attribute[] atts = obj.getAttributes();
                for (final Attribute att : atts) {
                    if (!(att instanceof LineNumberTable) && !(att instanceof LocalVariableTable)) {
                        addMessage("Attribute '" + tostring(att) + "' as an attribute of Code attribute '" + tostring(obj) + "' (method '" + m
                                + "') is unknown and will therefore be ignored.");
                    } else { // LineNumberTable or LocalVariableTable
                        addMessage("Attribute '" + tostring(att) + "' 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 (att instanceof LocalVariableTable) { // checks conforming to vmspec2 4.7.9

                        final LocalVariableTable lvt = (LocalVariableTable) att;

                        checkIndex(lvt, lvt.getNameIndex(), CONST_Utf8);

                        final 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 + "'.");
                        }

                        // In JustIce, the check for correct offsets into the code array is delayed to Pass 3a.
                        for (final LocalVariable localvariable : lvt.getLocalVariableTable()) {
                            checkIndex(lvt, localvariable.getNameIndex(), CONST_Utf8);
                            final String localname = ((ConstantUtf8) cp.getConstant(localvariable.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, localvariable.getSignatureIndex(), CONST_Utf8);
                            final String localsig = ((ConstantUtf8) cp.getConstant(localvariable.getSignatureIndex())).getBytes(); // Local sig.(=descriptor)
                            final Type t;
                            try {
                                t = Type.getType(localsig);
                            } catch (final ClassFormatException cfe) {
                                throw new ClassConstraintException("Illegal descriptor (==signature) '" + localsig + "' used by LocalVariable '"
                                        + tostring(localvariable) + "' referenced by '" + tostring(lvt) + "'.", cfe);
                            }
                            final int localindex = localvariable.getIndex();
                            if ((t == Type.LONG || t == Type.DOUBLE ? localindex + 1 : localindex) >= obj.getMaxLocals()) {
                                throw new ClassConstraintException("LocalVariableTable attribute '" + tostring(lvt) + "' references a LocalVariable '"
                                        + tostring(localvariable) + "' with an index that exceeds the surrounding Code attribute's max_locals value of '"
                                        + obj.getMaxLocals() + "'.");
                            }

                            try {
                                localVariablesInfos[methodNumber].add(localindex, localname, localvariable.getStartPC(), localvariable.getLength(), t);
                            } catch (final LocalVariableInfoInconsistentException lviie) {
                                throw new ClassConstraintException("Conflicting information in LocalVariableTable '" + tostring(lvt)
                                        + "' found in Code attribute '" + tostring(obj) + "' (method '" + tostring(m) + "'). " + lviie.getMessage(), lviie);
                            }
                        } // for all local variables localvariables[i] in the LocalVariableTable attribute atts[a] END

                        numOfLvtAttribs++;
                        if (!m.isStatic() && numOfLvtAttribs > 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 at most one LocalVariableTable attribute per local variable in the Code attribute.').");
                        }
                    } // if atts[a] instanceof LocalVariableTable END
                } // for all attributes atts[a] END

            } catch (final ClassNotFoundException e) {
                // FIXME: this might not be the best way to handle missing classes.
                throw new AssertionViolatedException("Missing class: " + e, e);
            }

        } // visitCode(Code) END