InstConstraintVisitor.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */
  17. package org.apache.bcel.verifier.structurals;

  18. import org.apache.bcel.Const;
  19. import org.apache.bcel.Repository;
  20. import org.apache.bcel.classfile.Constant;
  21. import org.apache.bcel.classfile.ConstantClass;
  22. import org.apache.bcel.classfile.ConstantDouble;
  23. import org.apache.bcel.classfile.ConstantDynamic;
  24. import org.apache.bcel.classfile.ConstantFieldref;
  25. import org.apache.bcel.classfile.ConstantFloat;
  26. import org.apache.bcel.classfile.ConstantInteger;
  27. import org.apache.bcel.classfile.ConstantLong;
  28. import org.apache.bcel.classfile.ConstantString;
  29. import org.apache.bcel.classfile.Field;
  30. import org.apache.bcel.classfile.JavaClass;
  31. //CHECKSTYLE:OFF (there are lots of references!)
  32. import org.apache.bcel.generic.*;
  33. //CHECKSTYLE:ON
  34. import org.apache.bcel.verifier.VerificationResult;
  35. import org.apache.bcel.verifier.Verifier;
  36. import org.apache.bcel.verifier.VerifierFactory;
  37. import org.apache.bcel.verifier.exc.AssertionViolatedException;
  38. import org.apache.bcel.verifier.exc.StructuralCodeConstraintException;

  39. /**
  40.  * A Visitor class testing for valid preconditions of JVM instructions. The instance of this class will throw a
  41.  * StructuralCodeConstraintException instance if an instruction is visitXXX()ed which has preconditions that are not
  42.  * satisfied. TODO: Currently, the JVM's behavior concerning monitors (MONITORENTER, MONITOREXIT) is not modeled in
  43.  * JustIce.
  44.  *
  45.  * @see StructuralCodeConstraintException
  46.  */
  47. public class InstConstraintVisitor extends EmptyVisitor {

  48.     private static final ObjectType GENERIC_ARRAY = ObjectType.getInstance(GenericArray.class.getName());

  49.     /**
  50.      * The Execution Frame we're working on.
  51.      *
  52.      * @see #setFrame(Frame f)
  53.      * @see #locals()
  54.      * @see #stack()
  55.      */
  56.     private Frame frame;

  57.     /**
  58.      * The ConstantPoolGen we're working on.
  59.      *
  60.      * @see #setConstantPoolGen(ConstantPoolGen cpg)
  61.      */
  62.     private ConstantPoolGen cpg;

  63.     /**
  64.      * The MethodGen we're working on.
  65.      *
  66.      * @see #setMethodGen(MethodGen mg)
  67.      */
  68.     private MethodGen mg;

  69.     /**
  70.      * The constructor. Constructs a new instance of this class.
  71.      */
  72.     public InstConstraintVisitor() {
  73.     }

  74.     /**
  75.      * Assures arrayref is of ArrayType or NULL; returns true if and only if arrayref is non-NULL.
  76.      *
  77.      * @throws StructuralCodeConstraintException if the above constraint is violated.
  78.      */
  79.     private boolean arrayrefOfArrayType(final Instruction o, final Type arrayref) {
  80.         if (!(arrayref instanceof ArrayType || arrayref.equals(Type.NULL))) {
  81.             constraintViolated(o, "The 'arrayref' does not refer to an array but is of type " + arrayref + ".");
  82.         }
  83.         return arrayref instanceof ArrayType;
  84.     }

  85.     /**
  86.      * This method is called by the visitXXX() to notify the acceptor of this InstConstraintVisitor that a constraint
  87.      * violation has occurred. This is done by throwing an instance of a StructuralCodeConstraintException.
  88.      *
  89.      * @throws StructuralCodeConstraintException always.
  90.      */
  91.     private void constraintViolated(final Instruction violator, final String description) {
  92.         final String fqClassName = violator.getClass().getName();
  93.         throw new StructuralCodeConstraintException(
  94.             "Instruction " + fqClassName.substring(fqClassName.lastIndexOf('.') + 1) + " constraint violated: " + description);
  95.     }

  96.     private ObjectType getObjectType(final FieldInstruction o) {
  97.         final ReferenceType rt = o.getReferenceType(cpg);
  98.         if (rt instanceof ObjectType) {
  99.             return (ObjectType) rt;
  100.         }
  101.         constraintViolated(o, "expecting ObjectType but got " + rt);
  102.         return null;
  103.     }

  104.     /**
  105.      * Assures index is of type INT.
  106.      *
  107.      * @throws StructuralCodeConstraintException if the above constraint is not satisfied.
  108.      */
  109.     private void indexOfInt(final Instruction o, final Type index) {
  110.         if (!index.equals(Type.INT)) {
  111.             constraintViolated(o, "The 'index' is not of type int but of type " + index + ".");
  112.         }
  113.     }

  114.     /**
  115.      * The LocalVariables we're working on.
  116.      *
  117.      * @see #setFrame(Frame f)
  118.      */
  119.     private LocalVariables locals() {
  120.         return frame.getLocals();
  121.     }

  122.     /**
  123.      * Assures the ReferenceType r is initialized (or Type.NULL). Formally, this means (!(r instanceof
  124.      * UninitializedObjectType)), because there are no uninitialized array types.
  125.      *
  126.      * @throws StructuralCodeConstraintException if the above constraint is not satisfied.
  127.      */
  128.     private void referenceTypeIsInitialized(final Instruction o, final ReferenceType r) {
  129.         if (r instanceof UninitializedObjectType) {
  130.             constraintViolated(o, "Working on an uninitialized object '" + r + "'.");
  131.         }
  132.     }

  133.     /**
  134.      * Sets the ConstantPoolGen instance needed for constraint checking prior to execution.
  135.      */
  136.     public void setConstantPoolGen(final ConstantPoolGen cpg) { // TODO could be package-protected?
  137.         this.cpg = cpg;
  138.     }

  139.     /**
  140.      * This returns the single instance of the InstConstraintVisitor class. To operate correctly, other values must have
  141.      * been set before actually using the instance. Use this method for performance reasons.
  142.      *
  143.      * @see #setConstantPoolGen(ConstantPoolGen cpg)
  144.      * @see #setMethodGen(MethodGen mg)
  145.      */
  146.     public void setFrame(final Frame f) { // TODO could be package-protected?
  147.         this.frame = f;
  148.         // if (singleInstance.mg == null || singleInstance.cpg == null)
  149.         // throw new AssertionViolatedException("Forgot to set important values first.");
  150.     }

  151.     /**
  152.      * Sets the MethodGen instance needed for constraint checking prior to execution.
  153.      */
  154.     public void setMethodGen(final MethodGen mg) {
  155.         this.mg = mg;
  156.     }

  157.     /**
  158.      * The OperandStack we're working on.
  159.      *
  160.      * @see #setFrame(Frame f)
  161.      */
  162.     private OperandStack stack() {
  163.         return frame.getStack();
  164.     }

  165.     /** Assures value is of type INT. */
  166.     private void valueOfInt(final Instruction o, final Type value) {
  167.         if (!value.equals(Type.INT)) {
  168.             constraintViolated(o, "The 'value' is not of type int but of type " + value + ".");
  169.         }
  170.     }

  171.     /***************************************************************/
  172.     /* "generic"visitXXXX methods where XXXX is an interface */
  173.     /* therefore, we don't know the order of visiting; but we know */
  174.     /* these methods are called before the visitYYYY methods below */
  175.     /***************************************************************/

  176.     /**
  177.      * Ensures the specific preconditions of the said instruction.
  178.      */
  179.     @Override
  180.     public void visitAALOAD(final AALOAD o) {
  181.         final Type arrayref = stack().peek(1);
  182.         final Type index = stack().peek(0);

  183.         indexOfInt(o, index);
  184.         if (arrayrefOfArrayType(o, arrayref) && !(((ArrayType) arrayref).getElementType() instanceof ReferenceType)) {
  185.             constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a ReferenceType but to an array of "
  186.                 + ((ArrayType) arrayref).getElementType() + ".");
  187.         }
  188.         // referenceTypeIsInitialized(o, (ReferenceType) (((ArrayType) arrayref).getElementType()));
  189.     }

  190.     /**
  191.      * Ensures the specific preconditions of the said instruction.
  192.      */
  193.     @Override
  194.     public void visitAASTORE(final AASTORE o) {
  195.         final Type arrayref = stack().peek(2);
  196.         final Type index = stack().peek(1);
  197.         final Type value = stack().peek(0);

  198.         indexOfInt(o, index);
  199.         if (!(value instanceof ReferenceType)) {
  200.             constraintViolated(o, "The 'value' is not of a ReferenceType but of type " + value + ".");
  201.         }
  202.         // } else {
  203.             // referenceTypeIsInitialized(o, (ReferenceType) value);
  204.         // }
  205.         //
  206.         // Don't bother further with "referenceTypeIsInitialized()", there are no arrays
  207.         // of an uninitialized object type.
  208.         if (arrayrefOfArrayType(o, arrayref) && !(((ArrayType) arrayref).getElementType() instanceof ReferenceType)) {
  209.             constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a ReferenceType but to an array of "
  210.                 + ((ArrayType) arrayref).getElementType() + ".");
  211.         }
  212.         // No check for array element assignment compatibility. This is done at runtime.
  213.     }

  214.     /**
  215.      * Ensures the specific preconditions of the said instruction.
  216.      */
  217.     @Override
  218.     public void visitACONST_NULL(final ACONST_NULL o) {
  219.         // Nothing needs to be done here.
  220.     }

  221.     /**
  222.      * Ensures the specific preconditions of the said instruction.
  223.      */
  224.     @Override
  225.     public void visitALOAD(final ALOAD o) {
  226.         // visitLoadInstruction(LoadInstruction) is called before.

  227.         // Nothing else needs to be done here.
  228.     }

  229.     /**
  230.      * Ensures the specific preconditions of the said instruction.
  231.      */
  232.     @Override
  233.     public void visitANEWARRAY(final ANEWARRAY o) {
  234.         if (!stack().peek().equals(Type.INT)) {
  235.             constraintViolated(o, "The 'count' at the stack top is not of type '" + Type.INT + "' but of type '" + stack().peek() + "'.");
  236.             // The runtime constant pool item at that index must be a symbolic reference to a class,
  237.             // array, or interface type. See Pass 3a.
  238.         }
  239.     }

  240.     /**
  241.      * Ensures the specific preconditions of the said instruction.
  242.      */
  243.     @Override
  244.     public void visitARETURN(final ARETURN o) {
  245.         if (!(stack().peek() instanceof ReferenceType)) {
  246.             constraintViolated(o, "The 'objectref' at the stack top is not of a ReferenceType but of type '" + stack().peek() + "'.");
  247.         }
  248.         final ReferenceType objectref = (ReferenceType) stack().peek();
  249.         referenceTypeIsInitialized(o, objectref);

  250.         // The check below should already done via visitReturnInstruction(ReturnInstruction), see there.
  251.         // It cannot be done using Staerk-et-al's "set of object types" instead of a
  252.         // "wider cast object type", anyway.
  253.         // if (! objectref.isAssignmentCompatibleWith(mg.getReturnType() )) {
  254.         // constraintViolated(o, "The 'objectref' type "+objectref+
  255.         // " at the stack top is not assignment compatible with the return type '"+mg.getReturnType()+"' of the method.");
  256.         // }
  257.     }

  258.     /**
  259.      * Ensures the specific preconditions of the said instruction.
  260.      */
  261.     @Override
  262.     public void visitARRAYLENGTH(final ARRAYLENGTH o) {
  263.         final Type arrayref = stack().peek(0);
  264.         arrayrefOfArrayType(o, arrayref);
  265.     }

  266.     /**
  267.      * Ensures the specific preconditions of the said instruction.
  268.      */
  269.     @Override
  270.     public void visitASTORE(final ASTORE o) {
  271.         if (!(stack().peek() instanceof ReferenceType || stack().peek() instanceof ReturnaddressType)) {
  272.             constraintViolated(o, "The 'objectref' is not of a ReferenceType or of ReturnaddressType but of " + stack().peek() + ".");
  273.         }
  274.         // if (stack().peek() instanceof ReferenceType) {
  275.         // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
  276.         // }
  277.     }

  278.     /**
  279.      * Ensures the specific preconditions of the said instruction.
  280.      */
  281.     @Override
  282.     public void visitATHROW(final ATHROW o) {
  283.         try {
  284.             // It's stated that 'objectref' must be of a ReferenceType --- but since Throwable is
  285.             // not derived from an ArrayType, it follows that 'objectref' must be of an ObjectType or Type.NULL.
  286.             if (!(stack().peek() instanceof ObjectType || stack().peek().equals(Type.NULL))) {
  287.                 constraintViolated(o, "The 'objectref' is not of an (initialized) ObjectType but of type " + stack().peek() + ".");
  288.             }

  289.             // NULL is a subclass of every class, so to speak.
  290.             if (stack().peek().equals(Type.NULL)) {
  291.                 return;
  292.             }

  293.             final ObjectType exc = (ObjectType) stack().peek();
  294.             final ObjectType throwable = (ObjectType) Type.getType("Ljava/lang/Throwable;");
  295.             if (!exc.subclassOf(throwable) && !exc.equals(throwable)) {
  296.                 constraintViolated(o, "The 'objectref' is not of class Throwable or of a subclass of Throwable, but of '" + stack().peek() + "'.");
  297.             }
  298.         } catch (final ClassNotFoundException e) {
  299.             // FIXME: maybe not the best way to handle this
  300.             throw new AssertionViolatedException("Missing class: " + e, e);
  301.         }
  302.     }

  303.     /**
  304.      * Ensures the specific preconditions of the said instruction.
  305.      */
  306.     @Override
  307.     public void visitBALOAD(final BALOAD o) {
  308.         final Type arrayref = stack().peek(1);
  309.         final Type index = stack().peek(0);
  310.         indexOfInt(o, index);
  311.         if (arrayrefOfArrayType(o, arrayref)
  312.             && !(((ArrayType) arrayref).getElementType().equals(Type.BOOLEAN) || ((ArrayType) arrayref).getElementType().equals(Type.BYTE))) {
  313.             constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a Type.BYTE or Type.BOOLEAN but to an array of '"
  314.                 + ((ArrayType) arrayref).getElementType() + "'.");
  315.         }
  316.     }

  317.     /**
  318.      * Ensures the specific preconditions of the said instruction.
  319.      */
  320.     @Override
  321.     public void visitBASTORE(final BASTORE o) {
  322.         final Type arrayref = stack().peek(2);
  323.         final Type index = stack().peek(1);
  324.         final Type value = stack().peek(0);

  325.         indexOfInt(o, index);
  326.         valueOfInt(o, value);
  327.         if (arrayrefOfArrayType(o, arrayref)
  328.             && !(((ArrayType) arrayref).getElementType().equals(Type.BOOLEAN) || ((ArrayType) arrayref).getElementType().equals(Type.BYTE))) {
  329.             constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a Type.BYTE or Type.BOOLEAN but to an array of '"
  330.                 + ((ArrayType) arrayref).getElementType() + "'.");
  331.         }
  332.     }

  333.     /***************************************************************/
  334.     /* "special"visitXXXX methods for one type of instruction each */
  335.     /***************************************************************/

  336.     /**
  337.      * Ensures the specific preconditions of the said instruction.
  338.      */
  339.     @Override
  340.     public void visitBIPUSH(final BIPUSH o) {
  341.         // Nothing to do...
  342.     }

  343.     /**
  344.      * Ensures the specific preconditions of the said instruction.
  345.      */
  346.     @Override
  347.     public void visitBREAKPOINT(final BREAKPOINT o) {
  348.         throw new AssertionViolatedException("In this JustIce verification pass there should not occur an illegal instruction such as BREAKPOINT.");
  349.     }

  350.     /**
  351.      * Ensures the specific preconditions of the said instruction.
  352.      */
  353.     @Override
  354.     public void visitCALOAD(final CALOAD o) {
  355.         final Type arrayref = stack().peek(1);
  356.         final Type index = stack().peek(0);

  357.         indexOfInt(o, index);
  358.         arrayrefOfArrayType(o, arrayref);
  359.     }

  360.     /**
  361.      * Ensures the specific preconditions of the said instruction.
  362.      */
  363.     @Override
  364.     public void visitCASTORE(final CASTORE o) {
  365.         final Type arrayref = stack().peek(2);
  366.         final Type index = stack().peek(1);
  367.         final Type value = stack().peek(0);

  368.         indexOfInt(o, index);
  369.         valueOfInt(o, value);
  370.         if (arrayrefOfArrayType(o, arrayref) && !((ArrayType) arrayref).getElementType().equals(Type.CHAR)) {
  371.             constraintViolated(o, "The 'arrayref' does not refer to an array with elements of type char but to an array of type "
  372.                 + ((ArrayType) arrayref).getElementType() + ".");
  373.         }
  374.     }

  375.     /**
  376.      * Ensures the specific preconditions of the said instruction.
  377.      */
  378.     @Override
  379.     public void visitCHECKCAST(final CHECKCAST o) {
  380.         // The objectref must be of type reference.
  381.         final Type objectref = stack().peek(0);
  382.         if (!(objectref instanceof ReferenceType)) {
  383.             constraintViolated(o, "The 'objectref' is not of a ReferenceType but of type " + objectref + ".");
  384.         }
  385.         // else{
  386.         // referenceTypeIsInitialized(o, (ReferenceType) objectref);
  387.         // }
  388.         // The unsigned indexbyte1 and indexbyte2 are used to construct an index into the runtime constant pool of the
  389.         // current class (�3.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The runtime constant
  390.         // pool item at the index must be a symbolic reference to a class, array, or interface type.
  391.         final Constant c = cpg.getConstant(o.getIndex());
  392.         if (!(c instanceof ConstantClass)) {
  393.             constraintViolated(o, "The Constant at 'index' is not a ConstantClass, but '" + c + "'.");
  394.         }
  395.     }

  396.     /***************************************************************/
  397.     /* "generic" visitYYYY methods where YYYY is a superclass. */
  398.     /* therefore, we know the order of visiting; we know */
  399.     /* these methods are called after the visitXXXX methods above. */
  400.     /***************************************************************/
  401.     /**
  402.      * Ensures the general preconditions of a CPInstruction instance.
  403.      */
  404.     @Override
  405.     public void visitCPInstruction(final CPInstruction o) {
  406.         final int idx = o.getIndex();
  407.         if (idx < 0 || idx >= cpg.getSize()) {
  408.             throw new AssertionViolatedException("Huh?! Constant pool index of instruction '" + o + "' illegal? Pass 3a should have checked this!");
  409.         }
  410.     }

  411.     /**
  412.      * Ensures the specific preconditions of the said instruction.
  413.      */
  414.     @Override
  415.     public void visitD2F(final D2F o) {
  416.         if (stack().peek() != Type.DOUBLE) {
  417.             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
  418.         }
  419.     }

  420.     /**
  421.      * Ensures the specific preconditions of the said instruction.
  422.      */
  423.     @Override
  424.     public void visitD2I(final D2I o) {
  425.         if (stack().peek() != Type.DOUBLE) {
  426.             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
  427.         }
  428.     }

  429.     /**
  430.      * Ensures the specific preconditions of the said instruction.
  431.      */
  432.     @Override
  433.     public void visitD2L(final D2L o) {
  434.         if (stack().peek() != Type.DOUBLE) {
  435.             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
  436.         }
  437.     }

  438.     /**
  439.      * Ensures the specific preconditions of the said instruction.
  440.      */
  441.     @Override
  442.     public void visitDADD(final DADD o) {
  443.         if (stack().peek() != Type.DOUBLE) {
  444.             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
  445.         }
  446.         if (stack().peek(1) != Type.DOUBLE) {
  447.             constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'.");
  448.         }
  449.     }

  450.     /**
  451.      * Ensures the specific preconditions of the said instruction.
  452.      */
  453.     @Override
  454.     public void visitDALOAD(final DALOAD o) {
  455.         indexOfInt(o, stack().peek());
  456.         if (stack().peek(1) == Type.NULL) {
  457.             return;
  458.         }
  459.         if (!(stack().peek(1) instanceof ArrayType)) {
  460.             constraintViolated(o, "Stack next-to-top must be of type double[] but is '" + stack().peek(1) + "'.");
  461.         }
  462.         final Type t = ((ArrayType) stack().peek(1)).getBasicType();
  463.         if (t != Type.DOUBLE) {
  464.             constraintViolated(o, "Stack next-to-top must be of type double[] but is '" + stack().peek(1) + "'.");
  465.         }
  466.     }

  467.     /**
  468.      * Ensures the specific preconditions of the said instruction.
  469.      */
  470.     @Override
  471.     public void visitDASTORE(final DASTORE o) {
  472.         if (stack().peek() != Type.DOUBLE) {
  473.             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
  474.         }
  475.         indexOfInt(o, stack().peek(1));
  476.         if (stack().peek(2) == Type.NULL) {
  477.             return;
  478.         }
  479.         if (!(stack().peek(2) instanceof ArrayType)) {
  480.             constraintViolated(o, "Stack next-to-next-to-top must be of type double[] but is '" + stack().peek(2) + "'.");
  481.         }
  482.         final Type t = ((ArrayType) stack().peek(2)).getBasicType();
  483.         if (t != Type.DOUBLE) {
  484.             constraintViolated(o, "Stack next-to-next-to-top must be of type double[] but is '" + stack().peek(2) + "'.");
  485.         }
  486.     }

  487.     /**
  488.      * Ensures the specific preconditions of the said instruction.
  489.      */
  490.     @Override
  491.     public void visitDCMPG(final DCMPG o) {
  492.         if (stack().peek() != Type.DOUBLE) {
  493.             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
  494.         }
  495.         if (stack().peek(1) != Type.DOUBLE) {
  496.             constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'.");
  497.         }
  498.     }

  499.     /**
  500.      * Ensures the specific preconditions of the said instruction.
  501.      */
  502.     @Override
  503.     public void visitDCMPL(final DCMPL o) {
  504.         if (stack().peek() != Type.DOUBLE) {
  505.             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
  506.         }
  507.         if (stack().peek(1) != Type.DOUBLE) {
  508.             constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'.");
  509.         }
  510.     }

  511.     /**
  512.      * Ensures the specific preconditions of the said instruction.
  513.      */
  514.     @Override
  515.     public void visitDCONST(final DCONST o) {
  516.         // There's nothing to be done here.
  517.     }

  518.     /**
  519.      * Ensures the specific preconditions of the said instruction.
  520.      */
  521.     @Override
  522.     public void visitDDIV(final DDIV o) {
  523.         if (stack().peek() != Type.DOUBLE) {
  524.             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
  525.         }
  526.         if (stack().peek(1) != Type.DOUBLE) {
  527.             constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'.");
  528.         }
  529.     }

  530.     /**
  531.      * Ensures the specific preconditions of the said instruction.
  532.      */
  533.     @Override
  534.     public void visitDLOAD(final DLOAD o) {
  535.         // visitLoadInstruction(LoadInstruction) is called before.

  536.         // Nothing else needs to be done here.
  537.     }

  538.     /**
  539.      * Ensures the specific preconditions of the said instruction.
  540.      */
  541.     @Override
  542.     public void visitDMUL(final DMUL o) {
  543.         if (stack().peek() != Type.DOUBLE) {
  544.             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
  545.         }
  546.         if (stack().peek(1) != Type.DOUBLE) {
  547.             constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'.");
  548.         }
  549.     }

  550.     /**
  551.      * Ensures the specific preconditions of the said instruction.
  552.      */
  553.     @Override
  554.     public void visitDNEG(final DNEG o) {
  555.         if (stack().peek() != Type.DOUBLE) {
  556.             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
  557.         }
  558.     }

  559.     /**
  560.      * Ensures the specific preconditions of the said instruction.
  561.      */
  562.     @Override
  563.     public void visitDREM(final DREM o) {
  564.         if (stack().peek() != Type.DOUBLE) {
  565.             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
  566.         }
  567.         if (stack().peek(1) != Type.DOUBLE) {
  568.             constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'.");
  569.         }
  570.     }

  571.     /**
  572.      * Ensures the specific preconditions of the said instruction.
  573.      */
  574.     @Override
  575.     public void visitDRETURN(final DRETURN o) {
  576.         if (stack().peek() != Type.DOUBLE) {
  577.             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
  578.         }
  579.     }

  580.     /**
  581.      * Ensures the specific preconditions of the said instruction.
  582.      */
  583.     @Override
  584.     public void visitDSTORE(final DSTORE o) {
  585.         // visitStoreInstruction(StoreInstruction) is called before.

  586.         // Nothing else needs to be done here.
  587.     }

  588.     /**
  589.      * Ensures the specific preconditions of the said instruction.
  590.      */
  591.     @Override
  592.     public void visitDSUB(final DSUB o) {
  593.         if (stack().peek() != Type.DOUBLE) {
  594.             constraintViolated(o, "The value at the stack top is not of type 'double', but of type '" + stack().peek() + "'.");
  595.         }
  596.         if (stack().peek(1) != Type.DOUBLE) {
  597.             constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '" + stack().peek(1) + "'.");
  598.         }
  599.     }

  600.     /**
  601.      * Ensures the specific preconditions of the said instruction.
  602.      */
  603.     @Override
  604.     public void visitDUP(final DUP o) {
  605.         if (stack().peek().getSize() != 1) {
  606.             constraintViolated(o,
  607.                 "Won't DUP type on stack top '" + stack().peek() + "' because it must occupy exactly one slot, not '" + stack().peek().getSize() + "'.");
  608.         }
  609.     }

  610.     /**
  611.      * Ensures the specific preconditions of the said instruction.
  612.      */
  613.     @Override
  614.     public void visitDUP_X1(final DUP_X1 o) {
  615.         if (stack().peek().getSize() != 1) {
  616.             constraintViolated(o, "Type on stack top '" + stack().peek() + "' should occupy exactly one slot, not '" + stack().peek().getSize() + "'.");
  617.         }
  618.         if (stack().peek(1).getSize() != 1) {
  619.             constraintViolated(o,
  620.                 "Type on stack next-to-top '" + stack().peek(1) + "' should occupy exactly one slot, not '" + stack().peek(1).getSize() + "'.");
  621.         }
  622.     }

  623.     /**
  624.      * Ensures the specific preconditions of the said instruction.
  625.      */
  626.     @Override
  627.     public void visitDUP_X2(final DUP_X2 o) {
  628.         if (stack().peek().getSize() != 1) {
  629.             constraintViolated(o, "Stack top type must be of size 1, but is '" + stack().peek() + "' of size '" + stack().peek().getSize() + "'.");
  630.         }
  631.         if (stack().peek(1).getSize() == 2) {
  632.             return; // Form 2, okay.
  633.         }
  634.         // stack().peek(1).getSize == 1.
  635.         if (stack().peek(2).getSize() != 1) {
  636.             constraintViolated(o, "If stack top's size is 1 and stack next-to-top's size is 1," + " stack next-to-next-to-top's size must also be 1, but is: '"
  637.                 + stack().peek(2) + "' of size '" + stack().peek(2).getSize() + "'.");
  638.         }
  639.     }

  640.     /**
  641.      * Ensures the specific preconditions of the said instruction.
  642.      */
  643.     @Override
  644.     public void visitDUP2(final DUP2 o) {
  645.         if (stack().peek().getSize() == 2) {
  646.             return; // Form 2, okay.
  647.         }
  648.         // stack().peek().getSize() == 1.
  649.         if (stack().peek(1).getSize() != 1) {
  650.             constraintViolated(o, "If stack top's size is 1, then stack next-to-top's size must also be 1. But it is '" + stack().peek(1) + "' of size '"
  651.                 + stack().peek(1).getSize() + "'.");
  652.         }
  653.     }

  654.     /**
  655.      * Ensures the specific preconditions of the said instruction.
  656.      */
  657.     @Override
  658.     public void visitDUP2_X1(final DUP2_X1 o) {
  659.         if (stack().peek().getSize() == 2) {
  660.             if (stack().peek(1).getSize() != 1) {
  661.                 constraintViolated(o, "If stack top's size is 2, then stack next-to-top's size must be 1. But it is '" + stack().peek(1) + "' of size '"
  662.                     + stack().peek(1).getSize() + "'.");
  663.             }
  664.         } else { // stack top is of size 1
  665.             if (stack().peek(1).getSize() != 1) {
  666.                 constraintViolated(o, "If stack top's size is 1, then stack next-to-top's size must also be 1. But it is '" + stack().peek(1) + "' of size '"
  667.                     + stack().peek(1).getSize() + "'.");
  668.             }
  669.             if (stack().peek(2).getSize() != 1) {
  670.                 constraintViolated(o, "If stack top's size is 1, then stack next-to-next-to-top's size must also be 1. But it is '" + stack().peek(2)
  671.                     + "' of size '" + stack().peek(2).getSize() + "'.");
  672.             }
  673.         }
  674.     }

  675.     /**
  676.      * Ensures the specific preconditions of the said instruction.
  677.      */
  678.     @Override
  679.     public void visitDUP2_X2(final DUP2_X2 o) {

  680.         if (stack().peek(0).getSize() == 2) {
  681.             // stack top size is 2, next-to-top's size is 1
  682.             if (stack().peek(1).getSize() == 2 || stack().peek(2).getSize() == 1) {
  683.                 return; // Form 2
  684.             }
  685.             constraintViolated(o, "If stack top's size is 2 and stack-next-to-top's size is 1,"
  686.                 + " then stack next-to-next-to-top's size must also be 1. But it is '" + stack().peek(2) + "' of size '" + stack().peek(2).getSize() + "'.");
  687.         } else if (stack().peek(1).getSize() == 1 && (stack().peek(2).getSize() == 2 || stack().peek(3).getSize() == 1)) {
  688.             return; // Form 1
  689.         }
  690.         constraintViolated(o, "The operand sizes on the stack do not match any of the four forms of usage of this instruction.");
  691.     }

  692.     /**
  693.      * Ensures the specific preconditions of the said instruction.
  694.      */
  695.     @Override
  696.     public void visitF2D(final F2D o) {
  697.         if (stack().peek() != Type.FLOAT) {
  698.             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
  699.         }
  700.     }

  701.     /**
  702.      * Ensures the specific preconditions of the said instruction.
  703.      */
  704.     @Override
  705.     public void visitF2I(final F2I o) {
  706.         if (stack().peek() != Type.FLOAT) {
  707.             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
  708.         }
  709.     }

  710.     /**
  711.      * Ensures the specific preconditions of the said instruction.
  712.      */
  713.     @Override
  714.     public void visitF2L(final F2L o) {
  715.         if (stack().peek() != Type.FLOAT) {
  716.             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
  717.         }
  718.     }

  719.     /**
  720.      * Ensures the specific preconditions of the said instruction.
  721.      */
  722.     @Override
  723.     public void visitFADD(final FADD o) {
  724.         if (stack().peek() != Type.FLOAT) {
  725.             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
  726.         }
  727.         if (stack().peek(1) != Type.FLOAT) {
  728.             constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'.");
  729.         }
  730.     }

  731.     /**
  732.      * Ensures the specific preconditions of the said instruction.
  733.      */
  734.     @Override
  735.     public void visitFALOAD(final FALOAD o) {
  736.         indexOfInt(o, stack().peek());
  737.         if (stack().peek(1) == Type.NULL) {
  738.             return;
  739.         }
  740.         if (!(stack().peek(1) instanceof ArrayType)) {
  741.             constraintViolated(o, "Stack next-to-top must be of type float[] but is '" + stack().peek(1) + "'.");
  742.         }
  743.         final Type t = ((ArrayType) stack().peek(1)).getBasicType();
  744.         if (t != Type.FLOAT) {
  745.             constraintViolated(o, "Stack next-to-top must be of type float[] but is '" + stack().peek(1) + "'.");
  746.         }
  747.     }

  748.     /**
  749.      * Ensures the specific preconditions of the said instruction.
  750.      */
  751.     @Override
  752.     public void visitFASTORE(final FASTORE o) {
  753.         if (stack().peek() != Type.FLOAT) {
  754.             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
  755.         }
  756.         indexOfInt(o, stack().peek(1));
  757.         if (stack().peek(2) == Type.NULL) {
  758.             return;
  759.         }
  760.         if (!(stack().peek(2) instanceof ArrayType)) {
  761.             constraintViolated(o, "Stack next-to-next-to-top must be of type float[] but is '" + stack().peek(2) + "'.");
  762.         }
  763.         final Type t = ((ArrayType) stack().peek(2)).getBasicType();
  764.         if (t != Type.FLOAT) {
  765.             constraintViolated(o, "Stack next-to-next-to-top must be of type float[] but is '" + stack().peek(2) + "'.");
  766.         }
  767.     }

  768.     /**
  769.      * Ensures the specific preconditions of the said instruction.
  770.      */
  771.     @Override
  772.     public void visitFCMPG(final FCMPG o) {
  773.         if (stack().peek() != Type.FLOAT) {
  774.             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
  775.         }
  776.         if (stack().peek(1) != Type.FLOAT) {
  777.             constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'.");
  778.         }
  779.     }

  780.     /**
  781.      * Ensures the specific preconditions of the said instruction.
  782.      */
  783.     @Override
  784.     public void visitFCMPL(final FCMPL o) {
  785.         if (stack().peek() != Type.FLOAT) {
  786.             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
  787.         }
  788.         if (stack().peek(1) != Type.FLOAT) {
  789.             constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'.");
  790.         }
  791.     }

  792.     /**
  793.      * Ensures the specific preconditions of the said instruction.
  794.      */
  795.     @Override
  796.     public void visitFCONST(final FCONST o) {
  797.         // nothing to do here.
  798.     }

  799.     /**
  800.      * Ensures the specific preconditions of the said instruction.
  801.      */
  802.     @Override
  803.     public void visitFDIV(final FDIV o) {
  804.         if (stack().peek() != Type.FLOAT) {
  805.             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
  806.         }
  807.         if (stack().peek(1) != Type.FLOAT) {
  808.             constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'.");
  809.         }
  810.     }

  811.     /**
  812.      * Ensures the general preconditions of a FieldInstruction instance.
  813.      */
  814.     @Override
  815.     public void visitFieldInstruction(final FieldInstruction o) {
  816.         // visitLoadClass(o) has been called before: Every FieldOrMethod
  817.         // implements LoadClass.
  818.         // visitCPInstruction(o) has been called before.
  819.         // A FieldInstruction may be: GETFIELD, GETSTATIC, PUTFIELD, PUTSTATIC
  820.         final Constant c = cpg.getConstant(o.getIndex());
  821.         if (!(c instanceof ConstantFieldref)) {
  822.             constraintViolated(o, "Index '" + o.getIndex() + "' should refer to a CONSTANT_Fieldref_info structure, but refers to '" + c + "'.");
  823.         }
  824.         // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).
  825.         final Type t = o.getType(cpg);
  826.         if (t instanceof ObjectType) {
  827.             final String name = ((ObjectType) t).getClassName();
  828.             final Verifier v = VerifierFactory.getVerifier(name);
  829.             final VerificationResult vr = v.doPass2();
  830.             if (vr.getStatus() != VerificationResult.VERIFIED_OK) {
  831.                 constraintViolated(o, "Class '" + name + "' is referenced, but cannot be loaded and resolved: '" + vr + "'.");
  832.             }
  833.         }
  834.     }

  835.     private Field visitFieldInstructionInternals(final FieldInstruction o) throws ClassNotFoundException {
  836.         final String fieldName = o.getFieldName(cpg);
  837.         final JavaClass jc = Repository.lookupClass(getObjectType(o).getClassName());
  838.         final Field f = jc.findField(fieldName, o.getType(cpg));
  839.         if (f == null) {
  840.             throw new AssertionViolatedException("Field '" + fieldName + "' not found in " + jc.getClassName());
  841.         }
  842.         final Type value = stack().peek();
  843.         final Type t = Type.getType(f.getSignature());
  844.         Type shouldBe = t;
  845.         if (shouldBe == Type.BOOLEAN || shouldBe == Type.BYTE || shouldBe == Type.CHAR || shouldBe == Type.SHORT) {
  846.             shouldBe = Type.INT;
  847.         }
  848.         if (t instanceof ReferenceType) {
  849.             if (value instanceof ReferenceType) {
  850.                 final ReferenceType rValue = (ReferenceType) value;
  851.                 referenceTypeIsInitialized(o, rValue);
  852.                 // TODO: This can possibly only be checked using Staerk-et-al's "set-of-object types", not
  853.                 // using "wider cast object types" created during verification.
  854.                 // Comment it out if you encounter problems. See also the analogon at visitPUTFIELD|visitPUTSTATIC.
  855.                 if (!rValue.isAssignmentCompatibleWith(shouldBe)) {
  856.                     constraintViolated(o, "The stack top type '" + value + "' is not assignment compatible with '" + shouldBe + "'.");
  857.                 }
  858.             } else {
  859.                 constraintViolated(o, "The stack top type '" + value + "' is not of a reference type as expected.");
  860.             }
  861.         } else if (shouldBe != value) {
  862.             constraintViolated(o, "The stack top type '" + value + "' is not of type '" + shouldBe + "' as expected.");
  863.         }
  864.         return f;
  865.     }

  866.     /**
  867.      * Ensures the specific preconditions of the said instruction.
  868.      */
  869.     @Override
  870.     public void visitFLOAD(final FLOAD o) {
  871.         // visitLoadInstruction(LoadInstruction) is called before.

  872.         // Nothing else needs to be done here.
  873.     }

  874.     /**
  875.      * Ensures the specific preconditions of the said instruction.
  876.      */
  877.     @Override
  878.     public void visitFMUL(final FMUL o) {
  879.         if (stack().peek() != Type.FLOAT) {
  880.             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
  881.         }
  882.         if (stack().peek(1) != Type.FLOAT) {
  883.             constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'.");
  884.         }
  885.     }

  886.     /**
  887.      * Ensures the specific preconditions of the said instruction.
  888.      */
  889.     @Override
  890.     public void visitFNEG(final FNEG o) {
  891.         if (stack().peek() != Type.FLOAT) {
  892.             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
  893.         }
  894.     }

  895.     /**
  896.      * Ensures the specific preconditions of the said instruction.
  897.      */
  898.     @Override
  899.     public void visitFREM(final FREM o) {
  900.         if (stack().peek() != Type.FLOAT) {
  901.             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
  902.         }
  903.         if (stack().peek(1) != Type.FLOAT) {
  904.             constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'.");
  905.         }
  906.     }

  907.     /**
  908.      * Ensures the specific preconditions of the said instruction.
  909.      */
  910.     @Override
  911.     public void visitFRETURN(final FRETURN o) {
  912.         if (stack().peek() != Type.FLOAT) {
  913.             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
  914.         }
  915.     }

  916.     /**
  917.      * Ensures the specific preconditions of the said instruction.
  918.      */
  919.     @Override
  920.     public void visitFSTORE(final FSTORE o) {
  921.         // visitStoreInstruction(StoreInstruction) is called before.

  922.         // Nothing else needs to be done here.
  923.     }

  924.     /**
  925.      * Ensures the specific preconditions of the said instruction.
  926.      */
  927.     @Override
  928.     public void visitFSUB(final FSUB o) {
  929.         if (stack().peek() != Type.FLOAT) {
  930.             constraintViolated(o, "The value at the stack top is not of type 'float', but of type '" + stack().peek() + "'.");
  931.         }
  932.         if (stack().peek(1) != Type.FLOAT) {
  933.             constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '" + stack().peek(1) + "'.");
  934.         }
  935.     }

  936.     /**
  937.      * Ensures the specific preconditions of the said instruction.
  938.      */
  939.     @Override
  940.     public void visitGETFIELD(final GETFIELD o) {
  941.         try {
  942.             final Type objectref = stack().peek();
  943.             if (!(objectref instanceof ObjectType || objectref == Type.NULL)) {
  944.                 constraintViolated(o, "Stack top should be an object reference that's not an array reference, but is '" + objectref + "'.");
  945.             }

  946.             final String fieldName = o.getFieldName(cpg);

  947.             final JavaClass jc = Repository.lookupClass(getObjectType(o).getClassName());
  948.             final Field f = jc.findField(fieldName, o.getType(cpg));
  949.             if (f == null) {
  950.                 throw new AssertionViolatedException("Field '" + fieldName + "' not found in " + jc.getClassName());
  951.             }

  952.             if (f.isProtected()) {
  953.                 final ObjectType classtype = getObjectType(o);
  954.                 final ObjectType curr = ObjectType.getInstance(mg.getClassName());

  955.                 if (classtype.equals(curr) || curr.subclassOf(classtype)) {
  956.                     final Type t = stack().peek();
  957.                     if (t == Type.NULL) {
  958.                         return;
  959.                     }
  960.                     if (!(t instanceof ObjectType)) {
  961.                         constraintViolated(o, "The 'objectref' must refer to an object that's not an array. Found instead: '" + t + "'.");
  962.                     }
  963.                     // final ObjectType objreftype = (ObjectType) t;
  964.                     // if (!(objreftype.equals(curr) || objreftype.subclassOf(curr))) {
  965.                         // TODO: One day move to Staerk-et-al's "Set of object types" instead of "wider" object types
  966.                         // created during the verification.
  967.                         // "Wider" object types don't allow us to check for things like that below.
  968.                         // constraintViolated(o, "The referenced field has the ACC_PROTECTED modifier, "+
  969.                         // "and it's a member of the current class or a superclass of the current class."+
  970.                         // " However, the referenced object type '"+stack().peek()+
  971.                         // "' is not the current class or a subclass of the current class.");
  972.                     //}
  973.                 }
  974.             }

  975.             // TODO: Could go into Pass 3a.
  976.             if (f.isStatic()) {
  977.                 constraintViolated(o, "Referenced field '" + f + "' is static which it shouldn't be.");
  978.             }

  979.         } catch (final ClassNotFoundException e) {
  980.             // FIXME: maybe not the best way to handle this
  981.             throw new AssertionViolatedException("Missing class: " + e, e);
  982.         }
  983.     }

  984.     /**
  985.      * Ensures the specific preconditions of the said instruction.
  986.      */
  987.     @Override
  988.     public void visitGETSTATIC(final GETSTATIC o) {
  989.         // Field must be static: see Pass 3a.
  990.     }

  991.     /**
  992.      * Ensures the specific preconditions of the said instruction.
  993.      */
  994.     @Override
  995.     public void visitGOTO(final GOTO o) {
  996.         // nothing to do here.
  997.     }

  998.     /**
  999.      * Ensures the specific preconditions of the said instruction.
  1000.      */
  1001.     @Override
  1002.     public void visitGOTO_W(final GOTO_W o) {
  1003.         // nothing to do here.
  1004.     }

  1005.     /**
  1006.      * Ensures the specific preconditions of the said instruction.
  1007.      */
  1008.     @Override
  1009.     public void visitI2B(final I2B o) {
  1010.         if (stack().peek() != Type.INT) {
  1011.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1012.         }
  1013.     }

  1014.     /**
  1015.      * Ensures the specific preconditions of the said instruction.
  1016.      */
  1017.     @Override
  1018.     public void visitI2C(final I2C o) {
  1019.         if (stack().peek() != Type.INT) {
  1020.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1021.         }
  1022.     }

  1023.     /**
  1024.      * Ensures the specific preconditions of the said instruction.
  1025.      */
  1026.     @Override
  1027.     public void visitI2D(final I2D o) {
  1028.         if (stack().peek() != Type.INT) {
  1029.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1030.         }
  1031.     }

  1032.     /**
  1033.      * Ensures the specific preconditions of the said instruction.
  1034.      */
  1035.     @Override
  1036.     public void visitI2F(final I2F o) {
  1037.         if (stack().peek() != Type.INT) {
  1038.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1039.         }
  1040.     }

  1041.     /**
  1042.      * Ensures the specific preconditions of the said instruction.
  1043.      */
  1044.     @Override
  1045.     public void visitI2L(final I2L o) {
  1046.         if (stack().peek() != Type.INT) {
  1047.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1048.         }
  1049.     }

  1050.     /**
  1051.      * Ensures the specific preconditions of the said instruction.
  1052.      */
  1053.     @Override
  1054.     public void visitI2S(final I2S o) {
  1055.         if (stack().peek() != Type.INT) {
  1056.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1057.         }
  1058.     }

  1059.     /**
  1060.      * Ensures the specific preconditions of the said instruction.
  1061.      */
  1062.     @Override
  1063.     public void visitIADD(final IADD o) {
  1064.         if (stack().peek() != Type.INT) {
  1065.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1066.         }
  1067.         if (stack().peek(1) != Type.INT) {
  1068.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1069.         }
  1070.     }

  1071.     /**
  1072.      * Ensures the specific preconditions of the said instruction.
  1073.      */
  1074.     @Override
  1075.     public void visitIALOAD(final IALOAD o) {
  1076.         indexOfInt(o, stack().peek());
  1077.         if (stack().peek(1) == Type.NULL) {
  1078.             return;
  1079.         }
  1080.         if (!(stack().peek(1) instanceof ArrayType)) {
  1081.             constraintViolated(o, "Stack next-to-top must be of type int[] but is '" + stack().peek(1) + "'.");
  1082.         }
  1083.         final Type t = ((ArrayType) stack().peek(1)).getBasicType();
  1084.         if (t != Type.INT) {
  1085.             constraintViolated(o, "Stack next-to-top must be of type int[] but is '" + stack().peek(1) + "'.");
  1086.         }
  1087.     }

  1088.     /**
  1089.      * Ensures the specific preconditions of the said instruction.
  1090.      */
  1091.     @Override
  1092.     public void visitIAND(final IAND o) {
  1093.         if (stack().peek() != Type.INT) {
  1094.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1095.         }
  1096.         if (stack().peek(1) != Type.INT) {
  1097.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1098.         }
  1099.     }

  1100.     /**
  1101.      * Ensures the specific preconditions of the said instruction.
  1102.      */
  1103.     @Override
  1104.     public void visitIASTORE(final IASTORE o) {
  1105.         if (stack().peek() != Type.INT) {
  1106.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1107.         }
  1108.         indexOfInt(o, stack().peek(1));
  1109.         if (stack().peek(2) == Type.NULL) {
  1110.             return;
  1111.         }
  1112.         if (!(stack().peek(2) instanceof ArrayType)) {
  1113.             constraintViolated(o, "Stack next-to-next-to-top must be of type int[] but is '" + stack().peek(2) + "'.");
  1114.         }
  1115.         final Type t = ((ArrayType) stack().peek(2)).getBasicType();
  1116.         if (t != Type.INT) {
  1117.             constraintViolated(o, "Stack next-to-next-to-top must be of type int[] but is '" + stack().peek(2) + "'.");
  1118.         }
  1119.     }

  1120.     /**
  1121.      * Ensures the specific preconditions of the said instruction.
  1122.      */
  1123.     @Override
  1124.     public void visitICONST(final ICONST o) {
  1125.         // nothing to do here.
  1126.     }

  1127.     /**
  1128.      * Ensures the specific preconditions of the said instruction.
  1129.      */
  1130.     @Override
  1131.     public void visitIDIV(final IDIV o) {
  1132.         if (stack().peek() != Type.INT) {
  1133.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1134.         }
  1135.         if (stack().peek(1) != Type.INT) {
  1136.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1137.         }
  1138.     }

  1139.     /**
  1140.      * Ensures the specific preconditions of the said instruction.
  1141.      */
  1142.     @Override
  1143.     public void visitIF_ACMPEQ(final IF_ACMPEQ o) {
  1144.         if (!(stack().peek() instanceof ReferenceType)) {
  1145.             constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '" + stack().peek() + "'.");
  1146.         }
  1147.         // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );

  1148.         if (!(stack().peek(1) instanceof ReferenceType)) {
  1149.             constraintViolated(o, "The value at the stack next-to-top is not of a ReferenceType, but of type '" + stack().peek(1) + "'.");
  1150.         }
  1151.         // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek(1)) );

  1152.     }

  1153.     /**
  1154.      * Ensures the specific preconditions of the said instruction.
  1155.      */
  1156.     @Override
  1157.     public void visitIF_ACMPNE(final IF_ACMPNE o) {
  1158.         if (!(stack().peek() instanceof ReferenceType)) {
  1159.             constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '" + stack().peek() + "'.");
  1160.             // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
  1161.         }
  1162.         if (!(stack().peek(1) instanceof ReferenceType)) {
  1163.             constraintViolated(o, "The value at the stack next-to-top is not of a ReferenceType, but of type '" + stack().peek(1) + "'.");
  1164.             // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek(1)) );
  1165.         }
  1166.     }

  1167.     /**
  1168.      * Ensures the specific preconditions of the said instruction.
  1169.      */
  1170.     @Override
  1171.     public void visitIF_ICMPEQ(final IF_ICMPEQ o) {
  1172.         if (stack().peek() != Type.INT) {
  1173.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1174.         }
  1175.         if (stack().peek(1) != Type.INT) {
  1176.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1177.         }
  1178.     }

  1179.     /**
  1180.      * Ensures the specific preconditions of the said instruction.
  1181.      */
  1182.     @Override
  1183.     public void visitIF_ICMPGE(final IF_ICMPGE o) {
  1184.         if (stack().peek() != Type.INT) {
  1185.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1186.         }
  1187.         if (stack().peek(1) != Type.INT) {
  1188.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1189.         }
  1190.     }

  1191.     /**
  1192.      * Ensures the specific preconditions of the said instruction.
  1193.      */
  1194.     @Override
  1195.     public void visitIF_ICMPGT(final IF_ICMPGT o) {
  1196.         if (stack().peek() != Type.INT) {
  1197.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1198.         }
  1199.         if (stack().peek(1) != Type.INT) {
  1200.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1201.         }
  1202.     }

  1203.     /**
  1204.      * Ensures the specific preconditions of the said instruction.
  1205.      */
  1206.     @Override
  1207.     public void visitIF_ICMPLE(final IF_ICMPLE o) {
  1208.         if (stack().peek() != Type.INT) {
  1209.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1210.         }
  1211.         if (stack().peek(1) != Type.INT) {
  1212.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1213.         }
  1214.     }

  1215.     /**
  1216.      * Ensures the specific preconditions of the said instruction.
  1217.      */
  1218.     @Override
  1219.     public void visitIF_ICMPLT(final IF_ICMPLT o) {
  1220.         if (stack().peek() != Type.INT) {
  1221.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1222.         }
  1223.         if (stack().peek(1) != Type.INT) {
  1224.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1225.         }
  1226.     }

  1227.     /**
  1228.      * Ensures the specific preconditions of the said instruction.
  1229.      */
  1230.     @Override
  1231.     public void visitIF_ICMPNE(final IF_ICMPNE o) {
  1232.         if (stack().peek() != Type.INT) {
  1233.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1234.         }
  1235.         if (stack().peek(1) != Type.INT) {
  1236.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1237.         }
  1238.     }

  1239.     /**
  1240.      * Ensures the specific preconditions of the said instruction.
  1241.      */
  1242.     @Override
  1243.     public void visitIFEQ(final IFEQ o) {
  1244.         if (stack().peek() != Type.INT) {
  1245.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1246.         }
  1247.     }

  1248.     /**
  1249.      * Ensures the specific preconditions of the said instruction.
  1250.      */
  1251.     @Override
  1252.     public void visitIFGE(final IFGE o) {
  1253.         if (stack().peek() != Type.INT) {
  1254.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1255.         }
  1256.     }

  1257.     /**
  1258.      * Ensures the specific preconditions of the said instruction.
  1259.      */
  1260.     @Override
  1261.     public void visitIFGT(final IFGT o) {
  1262.         if (stack().peek() != Type.INT) {
  1263.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1264.         }
  1265.     }

  1266.     /**
  1267.      * Ensures the specific preconditions of the said instruction.
  1268.      */
  1269.     @Override
  1270.     public void visitIFLE(final IFLE o) {
  1271.         if (stack().peek() != Type.INT) {
  1272.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1273.         }
  1274.     }

  1275.     /**
  1276.      * Ensures the specific preconditions of the said instruction.
  1277.      */
  1278.     @Override
  1279.     public void visitIFLT(final IFLT o) {
  1280.         if (stack().peek() != Type.INT) {
  1281.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1282.         }
  1283.     }

  1284.     /**
  1285.      * Ensures the specific preconditions of the said instruction.
  1286.      */
  1287.     @Override
  1288.     public void visitIFNE(final IFNE o) {
  1289.         if (stack().peek() != Type.INT) {
  1290.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1291.         }
  1292.     }

  1293.     /**
  1294.      * Ensures the specific preconditions of the said instruction.
  1295.      */
  1296.     @Override
  1297.     public void visitIFNONNULL(final IFNONNULL o) {
  1298.         if (!(stack().peek() instanceof ReferenceType)) {
  1299.             constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '" + stack().peek() + "'.");
  1300.         }
  1301.         referenceTypeIsInitialized(o, (ReferenceType) stack().peek());
  1302.     }

  1303.     /**
  1304.      * Ensures the specific preconditions of the said instruction.
  1305.      */
  1306.     @Override
  1307.     public void visitIFNULL(final IFNULL o) {
  1308.         if (!(stack().peek() instanceof ReferenceType)) {
  1309.             constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '" + stack().peek() + "'.");
  1310.         }
  1311.         referenceTypeIsInitialized(o, (ReferenceType) stack().peek());
  1312.     }

  1313.     /**
  1314.      * Ensures the specific preconditions of the said instruction.
  1315.      */
  1316.     @Override
  1317.     public void visitIINC(final IINC o) {
  1318.         // Mhhh. In BCEL, at this time "IINC" is not a LocalVariableInstruction.
  1319.         if (locals().maxLocals() <= (o.getType(cpg).getSize() == 1 ? o.getIndex() : o.getIndex() + 1)) {
  1320.             constraintViolated(o, "The 'index' is not a valid index into the local variable array.");
  1321.         }

  1322.         indexOfInt(o, locals().get(o.getIndex()));
  1323.     }

  1324.     /**
  1325.      * Ensures the specific preconditions of the said instruction.
  1326.      */
  1327.     @Override
  1328.     public void visitILOAD(final ILOAD o) {
  1329.         // All done by visitLocalVariableInstruction(), visitLoadInstruction()
  1330.     }

  1331.     /**
  1332.      * Ensures the specific preconditions of the said instruction.
  1333.      */
  1334.     @Override
  1335.     public void visitIMPDEP1(final IMPDEP1 o) {
  1336.         throw new AssertionViolatedException("In this JustIce verification pass there should not occur an illegal instruction such as IMPDEP1.");
  1337.     }

  1338.     /**
  1339.      * Ensures the specific preconditions of the said instruction.
  1340.      */
  1341.     @Override
  1342.     public void visitIMPDEP2(final IMPDEP2 o) {
  1343.         throw new AssertionViolatedException("In this JustIce verification pass there should not occur an illegal instruction such as IMPDEP2.");
  1344.     }

  1345.     /**
  1346.      * Ensures the specific preconditions of the said instruction.
  1347.      */
  1348.     @Override
  1349.     public void visitIMUL(final IMUL o) {
  1350.         if (stack().peek() != Type.INT) {
  1351.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1352.         }
  1353.         if (stack().peek(1) != Type.INT) {
  1354.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1355.         }
  1356.     }

  1357.     /**
  1358.      * Ensures the specific preconditions of the said instruction.
  1359.      */
  1360.     @Override
  1361.     public void visitINEG(final INEG o) {
  1362.         if (stack().peek() != Type.INT) {
  1363.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1364.         }
  1365.     }

  1366.     /**
  1367.      * Ensures the specific preconditions of the said instruction.
  1368.      */
  1369.     @Override
  1370.     public void visitINSTANCEOF(final INSTANCEOF o) {
  1371.         // The objectref must be of type reference.
  1372.         final Type objectref = stack().peek(0);
  1373.         if (!(objectref instanceof ReferenceType)) {
  1374.             constraintViolated(o, "The 'objectref' is not of a ReferenceType but of type " + objectref + ".");
  1375.         }
  1376.         // else{
  1377.         // referenceTypeIsInitialized(o, (ReferenceType) objectref);
  1378.         // }
  1379.         // The unsigned indexbyte1 and indexbyte2 are used to construct an index into the runtime constant pool of the
  1380.         // current class (�3.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The runtime constant
  1381.         // pool item at the index must be a symbolic reference to a class, array, or interface type.
  1382.         final Constant c = cpg.getConstant(o.getIndex());
  1383.         if (!(c instanceof ConstantClass)) {
  1384.             constraintViolated(o, "The Constant at 'index' is not a ConstantClass, but '" + c + "'.");
  1385.         }
  1386.     }

  1387.     /**
  1388.      * Ensures the specific preconditions of the said instruction.
  1389.      *
  1390.      * @since 6.0
  1391.      */
  1392.     @Override
  1393.     public void visitINVOKEDYNAMIC(final INVOKEDYNAMIC o) {
  1394.         throw new UnsupportedOperationException("INVOKEDYNAMIC instruction is not supported at this time");
  1395.     }

  1396.     /**
  1397.      * Ensures the general preconditions of an InvokeInstruction instance.
  1398.      */
  1399.     @Override
  1400.     public void visitInvokeInstruction(final InvokeInstruction o) {
  1401.         // visitLoadClass(o) has been called before: Every FieldOrMethod
  1402.         // implements LoadClass.
  1403.         // visitCPInstruction(o) has been called before.
  1404.         // TODO
  1405.     }

  1406.     /**
  1407.      * Ensures the specific preconditions of the said instruction.
  1408.      */
  1409.     @Override
  1410.     public void visitINVOKEINTERFACE(final INVOKEINTERFACE o) {
  1411.         // Method is not native, otherwise pass 3 would not happen.

  1412.         final int count = o.getCount();
  1413.         if (count == 0) {
  1414.             constraintViolated(o, "The 'count' argument must not be 0.");
  1415.         }
  1416.         // It is a ConstantInterfaceMethodref, Pass 3a made it sure.
  1417.         // TODO: Do we want to do anything with it?
  1418.         // ConstantInterfaceMethodref cimr = (ConstantInterfaceMethodref) (cpg.getConstant(o.getIndex()));

  1419.         // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).

  1420.         final Type t = o.getType(cpg);
  1421.         if (t instanceof ObjectType) {
  1422.             final String name = ((ObjectType) t).getClassName();
  1423.             final Verifier v = VerifierFactory.getVerifier(name);
  1424.             final VerificationResult vr = v.doPass2();
  1425.             if (vr.getStatus() != VerificationResult.VERIFIED_OK) {
  1426.                 constraintViolated(o, "Class '" + name + "' is referenced, but cannot be loaded and resolved: '" + vr + "'.");
  1427.             }
  1428.         }

  1429.         final Type[] argTypes = o.getArgumentTypes(cpg);
  1430.         final int argCount = argTypes.length;

  1431.         for (int i = argCount - 1; i >= 0; i--) {
  1432.             final Type fromStack = stack().peek(argCount - 1 - i); // 0 to argCount - 1
  1433.             Type fromDesc = argTypes[i];
  1434.             if (fromDesc == Type.BOOLEAN || fromDesc == Type.BYTE || fromDesc == Type.CHAR || fromDesc == Type.SHORT) {
  1435.                 fromDesc = Type.INT;
  1436.             }
  1437.             if (!fromStack.equals(fromDesc)) {
  1438.                 if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType) {
  1439.                     final ReferenceType rFromStack = (ReferenceType) fromStack;
  1440.                     // ReferenceType rFromDesc = (ReferenceType) fromDesc;
  1441.                     // TODO: This can only be checked when using Staerk-et-al's "set of object types"
  1442.                     // instead of a "wider cast object type" created during verification.
  1443.                     // if ( ! rFromStack.isAssignmentCompatibleWith(rFromDesc) ) {
  1444.                     // constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+
  1445.                     // "' on the stack (which is not assignment compatible).");
  1446.                     // }
  1447.                     referenceTypeIsInitialized(o, rFromStack);
  1448.                 } else {
  1449.                     constraintViolated(o, "Expecting a '" + fromDesc + "' but found a '" + fromStack + "' on the stack.");
  1450.                 }
  1451.             }
  1452.         }

  1453.         Type objRef = stack().peek(argCount);
  1454.         if (objRef == Type.NULL) {
  1455.             return;
  1456.         }
  1457.         if (!(objRef instanceof ReferenceType)) {
  1458.             constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '" + objRef + "'.");
  1459.         }
  1460.         referenceTypeIsInitialized(o, (ReferenceType) objRef);
  1461.         if (!(objRef instanceof ObjectType)) {
  1462.             if (!(objRef instanceof ArrayType)) { // could be a ReturnaddressType
  1463.                 constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '" + objRef + "'.");
  1464.             } else {
  1465.                 objRef = GENERIC_ARRAY;
  1466.             }
  1467.         }

  1468.         // String objRefClassName = ((ObjectType) objRef).getClassName();
  1469.         // String theInterface = o.getClassName(cpg);
  1470.         // TODO: This can only be checked if we're using Staerk-et-al's "set of object types"
  1471.         // instead of "wider cast object types" generated during verification.
  1472.         // if ( ! Repository.implementationOf(objRefClassName, theInterface) ) {
  1473.         // constraintViolated(o, "The 'objRef' item '" + objRef + "' does not implement '" + theInterface + "' as expected.");
  1474.         // }

  1475.         int countedCount = 1; // 1 for the objectref
  1476.         for (int i = 0; i < argCount; i++) {
  1477.             countedCount += argTypes[i].getSize();
  1478.         }
  1479.         if (count != countedCount) {
  1480.             constraintViolated(o, "The 'count' argument should probably read '" + countedCount + "' but is '" + count + "'.");
  1481.         }
  1482.     }

  1483.     private int visitInvokeInternals(final InvokeInstruction o) throws ClassNotFoundException {
  1484.         final Type t = o.getType(cpg);
  1485.         if (t instanceof ObjectType) {
  1486.             final String name = ((ObjectType) t).getClassName();
  1487.             final Verifier v = VerifierFactory.getVerifier(name);
  1488.             final VerificationResult vr = v.doPass2();
  1489.             if (vr.getStatus() != VerificationResult.VERIFIED_OK) {
  1490.                 constraintViolated(o, "Class '" + name + "' is referenced, but cannot be loaded and resolved: '" + vr + "'.");
  1491.             }
  1492.         }

  1493.         final Type[] argtypes = o.getArgumentTypes(cpg);
  1494.         final int nargs = argtypes.length;

  1495.         for (int i = nargs - 1; i >= 0; i--) {
  1496.             final Type fromStack = stack().peek(nargs - 1 - i); // 0 to nargs-1
  1497.             Type fromDesc = argtypes[i];
  1498.             if (fromDesc == Type.BOOLEAN || fromDesc == Type.BYTE || fromDesc == Type.CHAR || fromDesc == Type.SHORT) {
  1499.                 fromDesc = Type.INT;
  1500.             }
  1501.             if (!fromStack.equals(fromDesc)) {
  1502.                 if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType) {
  1503.                     final ReferenceType rFromStack = (ReferenceType) fromStack;
  1504.                     final ReferenceType rFromDesc = (ReferenceType) fromDesc;
  1505.                     // TODO: This can possibly only be checked when using Staerk-et-al's "set of object types" instead
  1506.                     // of a single "wider cast object type" created during verification.
  1507.                     if (!rFromStack.isAssignmentCompatibleWith(rFromDesc)) {
  1508.                         constraintViolated(o,
  1509.                             "Expecting a '" + fromDesc + "' but found a '" + fromStack + "' on the stack (which is not assignment compatible).");
  1510.                     }
  1511.                     referenceTypeIsInitialized(o, rFromStack);
  1512.                 } else {
  1513.                     constraintViolated(o, "Expecting a '" + fromDesc + "' but found a '" + fromStack + "' on the stack.");
  1514.                 }
  1515.             }
  1516.         }
  1517.         return nargs;
  1518.     }

  1519.     /**
  1520.      * Ensures the specific preconditions of the said instruction.
  1521.      */
  1522.     @Override
  1523.     public void visitINVOKESPECIAL(final INVOKESPECIAL o) {
  1524.         try {
  1525.             // Don't init an object twice.
  1526.             if (o.getMethodName(cpg).equals(Const.CONSTRUCTOR_NAME) && !(stack().peek(o.getArgumentTypes(cpg).length) instanceof UninitializedObjectType)) {
  1527.                 constraintViolated(o,
  1528.                     "Possibly initializing object twice."
  1529.                         + " A valid instruction sequence must not have an uninitialized object on the operand stack or in a local variable"
  1530.                         + " during a backwards branch, or in a local variable in code protected by an exception handler."
  1531.                         + " Please see The Java Virtual Machine Specification, Second Edition, 4.9.4 (pages 147 and 148) for details.");
  1532.             }

  1533.             // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).

  1534.             final int nargs = visitInvokeInternals(o);
  1535.             Type objref = stack().peek(nargs);
  1536.             if (objref == Type.NULL) {
  1537.                 return;
  1538.             }
  1539.             if (!(objref instanceof ReferenceType)) {
  1540.                 constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '" + objref + "'.");
  1541.             }
  1542.             String objRefClassName = null;
  1543.             if (!o.getMethodName(cpg).equals(Const.CONSTRUCTOR_NAME)) {
  1544.                 referenceTypeIsInitialized(o, (ReferenceType) objref);
  1545.                 if (!(objref instanceof ObjectType)) {
  1546.                     if (!(objref instanceof ArrayType)) { // could be a ReturnaddressType
  1547.                         constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '" + objref + "'.");
  1548.                     } else {
  1549.                         objref = GENERIC_ARRAY;
  1550.                     }
  1551.                 }

  1552.                 objRefClassName = ((ObjectType) objref).getClassName();
  1553.             } else {
  1554.                 if (!(objref instanceof UninitializedObjectType)) {
  1555.                     constraintViolated(o, "Expecting an UninitializedObjectType as 'objectref' on the stack, not a '" + objref
  1556.                         + "'. Otherwise, you couldn't invoke a method since an array has no methods (not to speak of a return address).");
  1557.                 }
  1558.                 objRefClassName = ((UninitializedObjectType) objref).getInitialized().getClassName();
  1559.             }

  1560.             final String theClass = o.getClassName(cpg);
  1561.             if (!Repository.instanceOf(objRefClassName, theClass)) {
  1562.                 constraintViolated(o, "The 'objref' item '" + objref + "' does not implement '" + theClass + "' as expected.");
  1563.             }

  1564.         } catch (final ClassNotFoundException e) {
  1565.             // FIXME: maybe not the best way to handle this
  1566.             throw new AssertionViolatedException("Missing class: " + e, e);
  1567.         }
  1568.     }

  1569.     /**
  1570.      * Ensures the specific preconditions of the said instruction.
  1571.      */
  1572.     @Override
  1573.     public void visitINVOKESTATIC(final INVOKESTATIC o) {
  1574.         try {
  1575.             // Method is not native, otherwise pass 3 would not happen.
  1576.             visitInvokeInternals(o);
  1577.         } catch (final ClassNotFoundException e) {
  1578.             // FIXME: maybe not the best way to handle this
  1579.             throw new AssertionViolatedException("Missing class: " + e, e);
  1580.         }
  1581.     }

  1582.     /**
  1583.      * Ensures the specific preconditions of the said instruction.
  1584.      */
  1585.     @Override
  1586.     public void visitINVOKEVIRTUAL(final INVOKEVIRTUAL o) {
  1587.         try {
  1588.             // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).

  1589.             final int nargs = visitInvokeInternals(o);
  1590.             Type objref = stack().peek(nargs);
  1591.             if (objref == Type.NULL) {
  1592.                 return;
  1593.             }
  1594.             if (!(objref instanceof ReferenceType)) {
  1595.                 constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '" + objref + "'.");
  1596.             }
  1597.             referenceTypeIsInitialized(o, (ReferenceType) objref);
  1598.             if (!(objref instanceof ObjectType)) {
  1599.                 if (!(objref instanceof ArrayType)) { // could be a ReturnaddressType
  1600.                     constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '" + objref + "'.");
  1601.                 } else {
  1602.                     objref = GENERIC_ARRAY;
  1603.                 }
  1604.             }

  1605.             final String objRefClassName = ((ObjectType) objref).getClassName();

  1606.             final String theClass = o.getClassName(cpg);

  1607.             if (objref != GENERIC_ARRAY && !Repository.instanceOf(objRefClassName, theClass)) {
  1608.                 constraintViolated(o, "The 'objref' item '" + objref + "' does not implement '" + theClass + "' as expected.");
  1609.             }
  1610.         } catch (final ClassNotFoundException e) {
  1611.             // FIXME: maybe not the best way to handle this
  1612.             throw new AssertionViolatedException("Missing class: " + e, e);
  1613.         }
  1614.     }

  1615.     /**
  1616.      * Ensures the specific preconditions of the said instruction.
  1617.      */
  1618.     @Override
  1619.     public void visitIOR(final IOR o) {
  1620.         if (stack().peek() != Type.INT) {
  1621.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1622.         }
  1623.         if (stack().peek(1) != Type.INT) {
  1624.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1625.         }
  1626.     }

  1627.     /**
  1628.      * Ensures the specific preconditions of the said instruction.
  1629.      */
  1630.     @Override
  1631.     public void visitIREM(final IREM o) {
  1632.         if (stack().peek() != Type.INT) {
  1633.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1634.         }
  1635.         if (stack().peek(1) != Type.INT) {
  1636.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1637.         }
  1638.     }

  1639.     /**
  1640.      * Ensures the specific preconditions of the said instruction.
  1641.      */
  1642.     @Override
  1643.     public void visitIRETURN(final IRETURN o) {
  1644.         if (stack().peek() != Type.INT) {
  1645.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1646.         }
  1647.     }

  1648.     /**
  1649.      * Ensures the specific preconditions of the said instruction.
  1650.      */
  1651.     @Override
  1652.     public void visitISHL(final ISHL o) {
  1653.         if (stack().peek() != Type.INT) {
  1654.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1655.         }
  1656.         if (stack().peek(1) != Type.INT) {
  1657.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1658.         }
  1659.     }

  1660.     /**
  1661.      * Ensures the specific preconditions of the said instruction.
  1662.      */
  1663.     @Override
  1664.     public void visitISHR(final ISHR o) {
  1665.         if (stack().peek() != Type.INT) {
  1666.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1667.         }
  1668.         if (stack().peek(1) != Type.INT) {
  1669.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1670.         }
  1671.     }

  1672.     /**
  1673.      * Ensures the specific preconditions of the said instruction.
  1674.      */
  1675.     @Override
  1676.     public void visitISTORE(final ISTORE o) {
  1677.         // visitStoreInstruction(StoreInstruction) is called before.

  1678.         // Nothing else needs to be done here.
  1679.     }

  1680.     /**
  1681.      * Ensures the specific preconditions of the said instruction.
  1682.      */
  1683.     @Override
  1684.     public void visitISUB(final ISUB o) {
  1685.         if (stack().peek() != Type.INT) {
  1686.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1687.         }
  1688.         if (stack().peek(1) != Type.INT) {
  1689.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1690.         }
  1691.     }

  1692.     /**
  1693.      * Ensures the specific preconditions of the said instruction.
  1694.      */
  1695.     @Override
  1696.     public void visitIUSHR(final IUSHR o) {
  1697.         if (stack().peek() != Type.INT) {
  1698.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1699.         }
  1700.         if (stack().peek(1) != Type.INT) {
  1701.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1702.         }
  1703.     }

  1704.     /**
  1705.      * Ensures the specific preconditions of the said instruction.
  1706.      */
  1707.     @Override
  1708.     public void visitIXOR(final IXOR o) {
  1709.         if (stack().peek() != Type.INT) {
  1710.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1711.         }
  1712.         if (stack().peek(1) != Type.INT) {
  1713.             constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '" + stack().peek(1) + "'.");
  1714.         }
  1715.     }

  1716.     /**
  1717.      * Ensures the specific preconditions of the said instruction.
  1718.      */
  1719.     @Override
  1720.     public void visitJSR(final JSR o) {
  1721.         // nothing to do here.
  1722.     }

  1723.     /**
  1724.      * Ensures the specific preconditions of the said instruction.
  1725.      */
  1726.     @Override
  1727.     public void visitJSR_W(final JSR_W o) {
  1728.         // nothing to do here.
  1729.     }

  1730.     /**
  1731.      * Ensures the specific preconditions of the said instruction.
  1732.      */
  1733.     @Override
  1734.     public void visitL2D(final L2D o) {
  1735.         if (stack().peek() != Type.LONG) {
  1736.             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
  1737.         }
  1738.     }

  1739.     /**
  1740.      * Ensures the specific preconditions of the said instruction.
  1741.      */
  1742.     @Override
  1743.     public void visitL2F(final L2F o) {
  1744.         if (stack().peek() != Type.LONG) {
  1745.             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
  1746.         }
  1747.     }

  1748.     /**
  1749.      * Ensures the specific preconditions of the said instruction.
  1750.      */
  1751.     @Override
  1752.     public void visitL2I(final L2I o) {
  1753.         if (stack().peek() != Type.LONG) {
  1754.             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
  1755.         }
  1756.     }

  1757.     /**
  1758.      * Ensures the specific preconditions of the said instruction.
  1759.      */
  1760.     @Override
  1761.     public void visitLADD(final LADD o) {
  1762.         if (stack().peek() != Type.LONG) {
  1763.             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
  1764.         }
  1765.         if (stack().peek(1) != Type.LONG) {
  1766.             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
  1767.         }
  1768.     }

  1769.     /**
  1770.      * Ensures the specific preconditions of the said instruction.
  1771.      */
  1772.     @Override
  1773.     public void visitLALOAD(final LALOAD o) {
  1774.         indexOfInt(o, stack().peek());
  1775.         if (stack().peek(1) == Type.NULL) {
  1776.             return;
  1777.         }
  1778.         if (!(stack().peek(1) instanceof ArrayType)) {
  1779.             constraintViolated(o, "Stack next-to-top must be of type long[] but is '" + stack().peek(1) + "'.");
  1780.         }
  1781.         final Type t = ((ArrayType) stack().peek(1)).getBasicType();
  1782.         if (t != Type.LONG) {
  1783.             constraintViolated(o, "Stack next-to-top must be of type long[] but is '" + stack().peek(1) + "'.");
  1784.         }
  1785.     }

  1786.     /**
  1787.      * Ensures the specific preconditions of the said instruction.
  1788.      */
  1789.     @Override
  1790.     public void visitLAND(final LAND o) {
  1791.         if (stack().peek() != Type.LONG) {
  1792.             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
  1793.         }
  1794.         if (stack().peek(1) != Type.LONG) {
  1795.             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
  1796.         }
  1797.     }

  1798.     /**
  1799.      * Ensures the specific preconditions of the said instruction.
  1800.      */
  1801.     @Override
  1802.     public void visitLASTORE(final LASTORE o) {
  1803.         if (stack().peek() != Type.LONG) {
  1804.             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
  1805.         }
  1806.         indexOfInt(o, stack().peek(1));
  1807.         if (stack().peek(2) == Type.NULL) {
  1808.             return;
  1809.         }
  1810.         if (!(stack().peek(2) instanceof ArrayType)) {
  1811.             constraintViolated(o, "Stack next-to-next-to-top must be of type long[] but is '" + stack().peek(2) + "'.");
  1812.         }
  1813.         final Type t = ((ArrayType) stack().peek(2)).getBasicType();
  1814.         if (t != Type.LONG) {
  1815.             constraintViolated(o, "Stack next-to-next-to-top must be of type long[] but is '" + stack().peek(2) + "'.");
  1816.         }
  1817.     }

  1818.     /**
  1819.      * Ensures the specific preconditions of the said instruction.
  1820.      */
  1821.     @Override
  1822.     public void visitLCMP(final LCMP o) {
  1823.         if (stack().peek() != Type.LONG) {
  1824.             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
  1825.         }
  1826.         if (stack().peek(1) != Type.LONG) {
  1827.             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
  1828.         }
  1829.     }

  1830.     /**
  1831.      * Ensures the specific preconditions of the said instruction.
  1832.      */
  1833.     @Override
  1834.     public void visitLCONST(final LCONST o) {
  1835.         // Nothing to do here.
  1836.     }

  1837.     /**
  1838.      * Ensures the specific preconditions of the said instruction.
  1839.      */
  1840.     @Override
  1841.     public void visitLDC(final LDC o) {
  1842.         // visitCPInstruction is called first.

  1843.         final Constant c = cpg.getConstant(o.getIndex());
  1844.         if (!(c instanceof ConstantInteger
  1845.                 || c instanceof ConstantFloat
  1846.                 || c instanceof ConstantString
  1847.                 || c instanceof ConstantClass
  1848.                 || c instanceof ConstantDynamic)) {
  1849.             constraintViolated(o,
  1850.                 "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float, a CONSTANT_String, a CONSTANT_Class, or a CONSTANT_Dynamic but is '"
  1851.                         + c + "'.");
  1852.         }
  1853.     }

  1854.     /**
  1855.      * Ensures the specific preconditions of the said instruction.
  1856.      */
  1857.     public void visitLDC_W(final LDC_W o) {
  1858.         // visitCPInstruction is called first.

  1859.         final Constant c = cpg.getConstant(o.getIndex());
  1860.         if (!(c instanceof ConstantInteger || c instanceof ConstantFloat || c instanceof ConstantString || c instanceof ConstantClass)) {
  1861.             constraintViolated(o,
  1862.                 "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float, a CONSTANT_String or a CONSTANT_Class, but is '" + c + "'.");
  1863.         }
  1864.     }

  1865.     /**
  1866.      * Ensures the specific preconditions of the said instruction.
  1867.      */
  1868.     @Override
  1869.     public void visitLDC2_W(final LDC2_W o) {
  1870.         // visitCPInstruction is called first.

  1871.         final Constant c = cpg.getConstant(o.getIndex());
  1872.         if (!(c instanceof ConstantLong || c instanceof ConstantDouble)) {
  1873.             constraintViolated(o, "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float or a CONSTANT_String, but is '" + c + "'.");
  1874.         }
  1875.     }

  1876.     /**
  1877.      * Ensures the specific preconditions of the said instruction.
  1878.      */
  1879.     @Override
  1880.     public void visitLDIV(final LDIV o) {
  1881.         if (stack().peek() != Type.LONG) {
  1882.             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
  1883.         }
  1884.         if (stack().peek(1) != Type.LONG) {
  1885.             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
  1886.         }
  1887.     }

  1888.     /**
  1889.      * Ensures the specific preconditions of the said instruction.
  1890.      */
  1891.     @Override
  1892.     public void visitLLOAD(final LLOAD o) {
  1893.         // visitLoadInstruction(LoadInstruction) is called before.

  1894.         // Nothing else needs to be done here.
  1895.     }

  1896.     /**
  1897.      * Ensures the specific preconditions of the said instruction.
  1898.      */
  1899.     @Override
  1900.     public void visitLMUL(final LMUL o) {
  1901.         if (stack().peek() != Type.LONG) {
  1902.             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
  1903.         }
  1904.         if (stack().peek(1) != Type.LONG) {
  1905.             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
  1906.         }
  1907.     }

  1908.     /**
  1909.      * Ensures the specific preconditions of the said instruction.
  1910.      */
  1911.     @Override
  1912.     public void visitLNEG(final LNEG o) {
  1913.         if (stack().peek() != Type.LONG) {
  1914.             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
  1915.         }
  1916.     }

  1917.     /**
  1918.      * Assures the generic preconditions of a LoadClass instance. The referenced class is loaded and pass2-verified.
  1919.      */
  1920.     @Override
  1921.     public void visitLoadClass(final LoadClass o) {
  1922.         final ObjectType t = o.getLoadClassType(cpg);
  1923.         if (t != null) { // null means "no class is loaded"
  1924.             final Verifier v = VerifierFactory.getVerifier(t.getClassName());
  1925.             final VerificationResult vr = v.doPass2();
  1926.             if (vr.getStatus() != VerificationResult.VERIFIED_OK) {
  1927.                 constraintViolated((Instruction) o,
  1928.                     "Class '" + o.getLoadClassType(cpg).getClassName() + "' is referenced, but cannot be loaded and resolved: '" + vr + "'.");
  1929.             }
  1930.         }
  1931.     }

  1932.     /**
  1933.      * Assures the generic preconditions of a LoadInstruction instance.
  1934.      */
  1935.     @Override
  1936.     public void visitLoadInstruction(final LoadInstruction o) {
  1937.         // visitLocalVariableInstruction(o) is called before, because it is more generic.

  1938.         // LOAD instructions must not read Type.UNKNOWN
  1939.         if (locals().get(o.getIndex()) == Type.UNKNOWN) {
  1940.             constraintViolated(o, "Read-Access on local variable " + o.getIndex() + " with unknown content.");
  1941.         }

  1942.         // LOAD instructions, two-slot-values at index N must have Type.UNKNOWN
  1943.         // as a symbol for the higher halve at index N+1
  1944.         // [suppose some instruction put an int at N+1--- our double at N is defective]
  1945.         if (o.getType(cpg).getSize() == 2 && locals().get(o.getIndex() + 1) != Type.UNKNOWN) {
  1946.             constraintViolated(o,
  1947.                 "Reading a two-locals value from local variables " + o.getIndex() + " and " + (o.getIndex() + 1) + " where the latter one is destroyed.");
  1948.         }

  1949.         // LOAD instructions must read the correct type.
  1950.         if (!(o instanceof ALOAD)) {
  1951.             if (locals().get(o.getIndex()) != o.getType(cpg)) {
  1952.                 constraintViolated(o, "Local Variable type and LOADing Instruction type mismatch: Local Variable: '" + locals().get(o.getIndex())
  1953.                     + "'; Instruction type: '" + o.getType(cpg) + "'.");
  1954.             }
  1955.         } else if (!(locals().get(o.getIndex()) instanceof ReferenceType)) {
  1956.             constraintViolated(o, "Local Variable type and LOADing Instruction type mismatch: Local Variable: '" + locals().get(o.getIndex())
  1957.                 + "'; Instruction expects a ReferenceType.");
  1958.         }
  1959.         // ALOAD __IS ALLOWED__ to put uninitialized objects onto the stack!
  1960.         // referenceTypeIsInitialized(o, (ReferenceType) (locals().get(o.getIndex())));

  1961.         // LOAD instructions must have enough free stack slots.
  1962.         if (stack().maxStack() - stack().slotsUsed() < o.getType(cpg).getSize()) {
  1963.             constraintViolated(o, "Not enough free stack slots to load a '" + o.getType(cpg) + "' onto the OperandStack.");
  1964.         }
  1965.     }

  1966.     /**
  1967.      * Assures the generic preconditions of a LocalVariableInstruction instance. That is, the index of the local variable
  1968.      * must be valid.
  1969.      */
  1970.     @Override
  1971.     public void visitLocalVariableInstruction(final LocalVariableInstruction o) {
  1972.         if (locals().maxLocals() <= (o.getType(cpg).getSize() == 1 ? o.getIndex() : o.getIndex() + 1)) {
  1973.             constraintViolated(o, "The 'index' is not a valid index into the local variable array.");
  1974.         }
  1975.     }

  1976.     /**
  1977.      * Ensures the specific preconditions of the said instruction.
  1978.      */
  1979.     @Override
  1980.     public void visitLOOKUPSWITCH(final LOOKUPSWITCH o) {
  1981.         if (stack().peek() != Type.INT) {
  1982.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  1983.         }
  1984.         // See also pass 3a.
  1985.     }

  1986.     /**
  1987.      * Ensures the specific preconditions of the said instruction.
  1988.      */
  1989.     @Override
  1990.     public void visitLOR(final LOR o) {
  1991.         if (stack().peek() != Type.LONG) {
  1992.             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
  1993.         }
  1994.         if (stack().peek(1) != Type.LONG) {
  1995.             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
  1996.         }
  1997.     }

  1998.     /**
  1999.      * Ensures the specific preconditions of the said instruction.
  2000.      */
  2001.     @Override
  2002.     public void visitLREM(final LREM o) {
  2003.         if (stack().peek() != Type.LONG) {
  2004.             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
  2005.         }
  2006.         if (stack().peek(1) != Type.LONG) {
  2007.             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
  2008.         }
  2009.     }

  2010.     /**
  2011.      * Ensures the specific preconditions of the said instruction.
  2012.      */
  2013.     @Override
  2014.     public void visitLRETURN(final LRETURN o) {
  2015.         if (stack().peek() != Type.LONG) {
  2016.             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
  2017.         }
  2018.     }

  2019.     /**
  2020.      * Ensures the specific preconditions of the said instruction.
  2021.      */
  2022.     @Override
  2023.     public void visitLSHL(final LSHL o) {
  2024.         if (stack().peek() != Type.INT) {
  2025.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  2026.         }
  2027.         if (stack().peek(1) != Type.LONG) {
  2028.             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
  2029.         }
  2030.     }

  2031.     /**
  2032.      * Ensures the specific preconditions of the said instruction.
  2033.      */
  2034.     @Override
  2035.     public void visitLSHR(final LSHR o) {
  2036.         if (stack().peek() != Type.INT) {
  2037.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  2038.         }
  2039.         if (stack().peek(1) != Type.LONG) {
  2040.             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
  2041.         }
  2042.     }

  2043.     /**
  2044.      * Ensures the specific preconditions of the said instruction.
  2045.      */
  2046.     @Override
  2047.     public void visitLSTORE(final LSTORE o) {
  2048.         // visitStoreInstruction(StoreInstruction) is called before.

  2049.         // Nothing else needs to be done here.
  2050.     }

  2051.     /**
  2052.      * Ensures the specific preconditions of the said instruction.
  2053.      */
  2054.     @Override
  2055.     public void visitLSUB(final LSUB o) {
  2056.         if (stack().peek() != Type.LONG) {
  2057.             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
  2058.         }
  2059.         if (stack().peek(1) != Type.LONG) {
  2060.             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
  2061.         }
  2062.     }

  2063.     /**
  2064.      * Ensures the specific preconditions of the said instruction.
  2065.      */
  2066.     @Override
  2067.     public void visitLUSHR(final LUSHR o) {
  2068.         if (stack().peek() != Type.INT) {
  2069.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  2070.         }
  2071.         if (stack().peek(1) != Type.LONG) {
  2072.             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
  2073.         }
  2074.     }

  2075.     /**
  2076.      * Ensures the specific preconditions of the said instruction.
  2077.      */
  2078.     @Override
  2079.     public void visitLXOR(final LXOR o) {
  2080.         if (stack().peek() != Type.LONG) {
  2081.             constraintViolated(o, "The value at the stack top is not of type 'long', but of type '" + stack().peek() + "'.");
  2082.         }
  2083.         if (stack().peek(1) != Type.LONG) {
  2084.             constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '" + stack().peek(1) + "'.");
  2085.         }
  2086.     }

  2087.     /**
  2088.      * Ensures the specific preconditions of the said instruction.
  2089.      */
  2090.     @Override
  2091.     public void visitMONITORENTER(final MONITORENTER o) {
  2092.         if (!(stack().peek() instanceof ReferenceType)) {
  2093.             constraintViolated(o, "The stack top should be of a ReferenceType, but is '" + stack().peek() + "'.");
  2094.         }
  2095.         // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
  2096.     }

  2097.     /**
  2098.      * Ensures the specific preconditions of the said instruction.
  2099.      */
  2100.     @Override
  2101.     public void visitMONITOREXIT(final MONITOREXIT o) {
  2102.         if (!(stack().peek() instanceof ReferenceType)) {
  2103.             constraintViolated(o, "The stack top should be of a ReferenceType, but is '" + stack().peek() + "'.");
  2104.         }
  2105.         // referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
  2106.     }

  2107.     /**
  2108.      * Ensures the specific preconditions of the said instruction.
  2109.      */
  2110.     @Override
  2111.     public void visitMULTIANEWARRAY(final MULTIANEWARRAY o) {
  2112.         final int dimensions = o.getDimensions();
  2113.         // Dimensions argument is okay: see Pass 3a.
  2114.         for (int i = 0; i < dimensions; i++) {
  2115.             if (stack().peek(i) != Type.INT) {
  2116.                 constraintViolated(o, "The '" + dimensions + "' upper stack types should be 'int' but aren't.");
  2117.             }
  2118.         }
  2119.         // The runtime constant pool item at that index must be a symbolic reference to a class,
  2120.         // array, or interface type. See Pass 3a.
  2121.     }

  2122.     /**
  2123.      * Ensures the specific preconditions of the said instruction.
  2124.      */
  2125.     @Override
  2126.     public void visitNEW(final NEW o) {
  2127.         // visitCPInstruction(CPInstruction) has been called before.
  2128.         // visitLoadClass(LoadClass) has been called before.

  2129.         final Type t = o.getType(cpg);
  2130.         if (!(t instanceof ReferenceType)) {
  2131.             throw new AssertionViolatedException("NEW.getType() returning a non-reference type?!");
  2132.         }
  2133.         if (!(t instanceof ObjectType)) {
  2134.             constraintViolated(o, "Expecting a class type (ObjectType) to work on. Found: '" + t + "'.");
  2135.         }
  2136.         final ObjectType obj = (ObjectType) t;

  2137.         // e.g.: Don't instantiate interfaces
  2138.         try {
  2139.             if (!obj.referencesClassExact()) {
  2140.                 constraintViolated(o, "Expecting a class type (ObjectType) to work on. Found: '" + obj + "'.");
  2141.             }
  2142.         } catch (final ClassNotFoundException e) {
  2143.             constraintViolated(o, "Expecting a class type (ObjectType) to work on. Found: '" + obj + "'." + " which threw " + e);
  2144.         }
  2145.     }

  2146.     /**
  2147.      * Ensures the specific preconditions of the said instruction.
  2148.      */
  2149.     @Override
  2150.     public void visitNEWARRAY(final NEWARRAY o) {
  2151.         if (stack().peek() != Type.INT) {
  2152.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  2153.         }
  2154.     }

  2155.     /**
  2156.      * Ensures the specific preconditions of the said instruction.
  2157.      */
  2158.     @Override
  2159.     public void visitNOP(final NOP o) {
  2160.         // nothing is to be done here.
  2161.     }

  2162.     /**
  2163.      * Ensures the specific preconditions of the said instruction.
  2164.      */
  2165.     @Override
  2166.     public void visitPOP(final POP o) {
  2167.         if (stack().peek().getSize() != 1) {
  2168.             constraintViolated(o, "Stack top size should be 1 but stack top is '" + stack().peek() + "' of size '" + stack().peek().getSize() + "'.");
  2169.         }
  2170.     }

  2171.     /**
  2172.      * Ensures the specific preconditions of the said instruction.
  2173.      */
  2174.     @Override
  2175.     public void visitPOP2(final POP2 o) {
  2176.         if (stack().peek().getSize() != 2) {
  2177.             constraintViolated(o, "Stack top size should be 2 but stack top is '" + stack().peek() + "' of size '" + stack().peek().getSize() + "'.");
  2178.         }
  2179.     }

  2180.     /**
  2181.      * Ensures the specific preconditions of the said instruction.
  2182.      */
  2183.     @Override
  2184.     public void visitPUTFIELD(final PUTFIELD o) {
  2185.         try {

  2186.             final Type objectref = stack().peek(1);
  2187.             if (!(objectref instanceof ObjectType || objectref == Type.NULL)) {
  2188.                 constraintViolated(o, "Stack next-to-top should be an object reference that's not an array reference, but is '" + objectref + "'.");
  2189.             }

  2190.             final Field f = visitFieldInstructionInternals(o);

  2191.             if (f.isProtected()) {
  2192.                 final ObjectType classtype = getObjectType(o);
  2193.                 final ObjectType curr = ObjectType.getInstance(mg.getClassName());

  2194.                 if (classtype.equals(curr) || curr.subclassOf(classtype)) {
  2195.                     final Type tp = stack().peek(1);
  2196.                     if (tp == Type.NULL) {
  2197.                         return;
  2198.                     }
  2199.                     if (!(tp instanceof ObjectType)) {
  2200.                         constraintViolated(o, "The 'objectref' must refer to an object that's not an array. Found instead: '" + tp + "'.");
  2201.                     }
  2202.                     final ObjectType objreftype = (ObjectType) tp;
  2203.                     if (!(objreftype.equals(curr) || objreftype.subclassOf(curr))) {
  2204.                         constraintViolated(o,
  2205.                             "The referenced field has the ACC_PROTECTED modifier, and it's a member of the current class or"
  2206.                                 + " a superclass of the current class. However, the referenced object type '" + stack().peek()
  2207.                                 + "' is not the current class or a subclass of the current class.");
  2208.                     }
  2209.                 }
  2210.             }

  2211.             // TODO: Could go into Pass 3a.
  2212.             if (f.isStatic()) {
  2213.                 constraintViolated(o, "Referenced field '" + f + "' is static which it shouldn't be.");
  2214.             }

  2215.         } catch (final ClassNotFoundException e) {
  2216.             // FIXME: maybe not the best way to handle this
  2217.             throw new AssertionViolatedException("Missing class: " + e, e);
  2218.         }
  2219.     }

  2220.     /**
  2221.      * Ensures the specific preconditions of the said instruction.
  2222.      */
  2223.     @Override
  2224.     public void visitPUTSTATIC(final PUTSTATIC o) {
  2225.         try {
  2226.             visitFieldInstructionInternals(o);
  2227.         } catch (final ClassNotFoundException e) {
  2228.             // FIXME: maybe not the best way to handle this
  2229.             throw new AssertionViolatedException("Missing class: " + e, e);
  2230.         }
  2231.     }

  2232.     /**
  2233.      * Ensures the specific preconditions of the said instruction.
  2234.      */
  2235.     @Override
  2236.     public void visitRET(final RET o) {
  2237.         if (!(locals().get(o.getIndex()) instanceof ReturnaddressType)) {
  2238.             constraintViolated(o, "Expecting a ReturnaddressType in local variable " + o.getIndex() + ".");
  2239.         }
  2240.         if (locals().get(o.getIndex()) == ReturnaddressType.NO_TARGET) {
  2241.             throw new AssertionViolatedException("RET expecting a target!");
  2242.         }
  2243.         // Other constraints such as non-allowed overlapping subroutines are enforced
  2244.         // while building the Subroutines data structure.
  2245.     }

  2246.     /**
  2247.      * Ensures the specific preconditions of the said instruction.
  2248.      */
  2249.     @Override
  2250.     public void visitRETURN(final RETURN o) {
  2251.         if (mg.getName().equals(Const.CONSTRUCTOR_NAME) && Frame.getThis() != null && !mg.getClassName().equals(Type.OBJECT.getClassName())) {
  2252.             constraintViolated(o, "Leaving a constructor that itself did not call a constructor.");
  2253.         }
  2254.     }

  2255.     /**
  2256.      * Assures the generic preconditions of a ReturnInstruction instance.
  2257.      */
  2258.     @Override
  2259.     public void visitReturnInstruction(final ReturnInstruction o) {
  2260.         Type methodType = mg.getType();
  2261.         if (methodType == Type.BOOLEAN || methodType == Type.BYTE || methodType == Type.SHORT || methodType == Type.CHAR) {
  2262.             methodType = Type.INT;
  2263.         }

  2264.         if (o instanceof RETURN) {
  2265.             if (methodType == Type.VOID) {
  2266.                 return;
  2267.             }
  2268.             constraintViolated(o, "RETURN instruction in non-void method.");
  2269.         }
  2270.         if (o instanceof ARETURN) {
  2271.             if (methodType == Type.VOID) {
  2272.                 constraintViolated(o, "ARETURN instruction in void method.");
  2273.             }
  2274.             if (stack().peek() == Type.NULL) {
  2275.                 return;
  2276.             }
  2277.             if (!(stack().peek() instanceof ReferenceType)) {
  2278.                 constraintViolated(o, "Reference type expected on top of stack, but is: '" + stack().peek() + "'.");
  2279.             }
  2280.             referenceTypeIsInitialized(o, (ReferenceType) stack().peek());
  2281.             // ReferenceType objectref = (ReferenceType) (stack().peek());
  2282.             // TODO: This can only be checked if using Staerk-et-al's "set of object types" instead of a
  2283.             // "wider cast object type" created during verification.
  2284.             // if (! (objectref.isAssignmentCompatibleWith(mg.getType())) ) {
  2285.             // constraintViolated(o, "Type on stack top which should be returned is a '"+stack().peek()+
  2286.             // "' which is not assignment compatible with the return type of this method, '"+mg.getType()+"'.");
  2287.             // }
  2288.         } else if (!methodType.equals(stack().peek())) {
  2289.             constraintViolated(o, "Current method has return type of '" + mg.getType() + "' expecting a '" + methodType
  2290.                 + "' on top of the stack. But stack top is a '" + stack().peek() + "'.");
  2291.         }
  2292.     }

  2293.     /**
  2294.      * Ensures the specific preconditions of the said instruction.
  2295.      */
  2296.     @Override
  2297.     public void visitSALOAD(final SALOAD o) {
  2298.         indexOfInt(o, stack().peek());
  2299.         if (stack().peek(1) == Type.NULL) {
  2300.             return;
  2301.         }
  2302.         if (!(stack().peek(1) instanceof ArrayType)) {
  2303.             constraintViolated(o, "Stack next-to-top must be of type short[] but is '" + stack().peek(1) + "'.");
  2304.         }
  2305.         final Type t = ((ArrayType) stack().peek(1)).getBasicType();
  2306.         if (t != Type.SHORT) {
  2307.             constraintViolated(o, "Stack next-to-top must be of type short[] but is '" + stack().peek(1) + "'.");
  2308.         }
  2309.     }

  2310.     /**
  2311.      * Ensures the specific preconditions of the said instruction.
  2312.      */
  2313.     @Override
  2314.     public void visitSASTORE(final SASTORE o) {
  2315.         if (stack().peek() != Type.INT) {
  2316.             constraintViolated(o, "The value at the stack top is not of type 'int', but of type '" + stack().peek() + "'.");
  2317.         }
  2318.         indexOfInt(o, stack().peek(1));
  2319.         if (stack().peek(2) == Type.NULL) {
  2320.             return;
  2321.         }
  2322.         if (!(stack().peek(2) instanceof ArrayType)) {
  2323.             constraintViolated(o, "Stack next-to-next-to-top must be of type short[] but is '" + stack().peek(2) + "'.");
  2324.         }
  2325.         final Type t = ((ArrayType) stack().peek(2)).getBasicType();
  2326.         if (t != Type.SHORT) {
  2327.             constraintViolated(o, "Stack next-to-next-to-top must be of type short[] but is '" + stack().peek(2) + "'.");
  2328.         }
  2329.     }

  2330.     /**
  2331.      * Ensures the specific preconditions of the said instruction.
  2332.      */
  2333.     @Override
  2334.     public void visitSIPUSH(final SIPUSH o) {
  2335.         // nothing to do here. Generic visitXXX() methods did the trick before.
  2336.     }

  2337.     /***************************************************************/
  2338.     /* MISC */
  2339.     /***************************************************************/
  2340.     /**
  2341.      * Ensures the general preconditions of an instruction that accesses the stack. This method is here because BCEL has no
  2342.      * such superinterface for the stack accessing instructions; and there are funny unexpected exceptions in the semantices
  2343.      * of the superinterfaces and superclasses provided. E.g. SWAP is a StackConsumer, but DUP_X1 is not a StackProducer.
  2344.      * Therefore, this method is called by all StackProducer, StackConsumer, and StackInstruction instances via their
  2345.      * visitXXX() method. Unfortunately, as the superclasses and superinterfaces overlap, some instructions cause this
  2346.      * method to be called two or three times. [TODO: Fix this.]
  2347.      *
  2348.      * @see #visitStackConsumer(StackConsumer o)
  2349.      * @see #visitStackProducer(StackProducer o)
  2350.      * @see #visitStackInstruction(StackInstruction o)
  2351.      */
  2352.     private void visitStackAccessor(final Instruction o) {
  2353.         final int consume = o.consumeStack(cpg); // Stack values are always consumed first; then produced.
  2354.         if (consume > stack().slotsUsed()) {
  2355.             constraintViolated(o, "Cannot consume " + consume + " stack slots: only " + stack().slotsUsed() + " slot(s) left on stack!\nStack:\n" + stack());
  2356.         }

  2357.         final int produce = o.produceStack(cpg) - o.consumeStack(cpg); // Stack values are always consumed first; then produced.
  2358.         if (produce + stack().slotsUsed() > stack().maxStack()) {
  2359.             constraintViolated(o, "Cannot produce " + produce + " stack slots: only " + (stack().maxStack() - stack().slotsUsed())
  2360.                 + " free stack slot(s) left.\nStack:\n" + stack());
  2361.         }
  2362.     }

  2363.     /**
  2364.      * Ensures the general preconditions of a StackConsumer instance.
  2365.      */
  2366.     @Override
  2367.     public void visitStackConsumer(final StackConsumer o) {
  2368.         visitStackAccessor((Instruction) o);
  2369.     }

  2370.     /**
  2371.      * Ensures the general preconditions of a StackInstruction instance.
  2372.      */
  2373.     @Override
  2374.     public void visitStackInstruction(final StackInstruction o) {
  2375.         visitStackAccessor(o);
  2376.     }

  2377.     /**
  2378.      * Ensures the general preconditions of a StackProducer instance.
  2379.      */
  2380.     @Override
  2381.     public void visitStackProducer(final StackProducer o) {
  2382.         visitStackAccessor((Instruction) o);
  2383.     }

  2384.     /**
  2385.      * Assures the generic preconditions of a StoreInstruction instance.
  2386.      */
  2387.     @Override
  2388.     public void visitStoreInstruction(final StoreInstruction o) {
  2389.         // visitLocalVariableInstruction(o) is called before, because it is more generic.

  2390.         if (stack().isEmpty()) { // Don't bother about 1 or 2 stack slots used. This check is implicitly done below while type checking.
  2391.             constraintViolated(o, "Cannot STORE: Stack to read from is empty.");
  2392.         }

  2393.         if (!(o instanceof ASTORE)) {
  2394.             if (!(stack().peek() == o.getType(cpg))) { // the other xSTORE types are singletons in BCEL.
  2395.                 constraintViolated(o,
  2396.                     "Stack top type and STOREing Instruction type mismatch: Stack top: '" + stack().peek() + "'; Instruction type: '" + o.getType(cpg) + "'.");
  2397.             }
  2398.         } else { // we deal with ASTORE
  2399.             final Type stacktop = stack().peek();
  2400.             if (!(stacktop instanceof ReferenceType) && !(stacktop instanceof ReturnaddressType)) {
  2401.                 constraintViolated(o, "Stack top type and STOREing Instruction type mismatch: Stack top: '" + stack().peek()
  2402.                     + "'; Instruction expects a ReferenceType or a ReturnadressType.");
  2403.             }
  2404.             // if (stacktop instanceof ReferenceType) {
  2405.             // referenceTypeIsInitialized(o, (ReferenceType) stacktop);
  2406.             // }
  2407.         }
  2408.     }

  2409.     /**
  2410.      * Ensures the specific preconditions of the said instruction.
  2411.      */
  2412.     @Override
  2413.     public void visitSWAP(final SWAP o) {
  2414.         if (stack().peek().getSize() != 1) {
  2415.             constraintViolated(o, "The value at the stack top is not of size '1', but of size '" + stack().peek().getSize() + "'.");
  2416.         }
  2417.         if (stack().peek(1).getSize() != 1) {
  2418.             constraintViolated(o, "The value at the stack next-to-top is not of size '1', but of size '" + stack().peek(1).getSize() + "'.");
  2419.         }
  2420.     }

  2421.     /**
  2422.      * Ensures the specific preconditions of the said instruction.
  2423.      */
  2424.     @Override
  2425.     public void visitTABLESWITCH(final TABLESWITCH o) {
  2426.         indexOfInt(o, stack().peek());
  2427.         // See Pass 3a.
  2428.     }

  2429. }