aboutsummaryrefslogtreecommitdiff
path: root/src/java/org/apache/bcel/verifier
diff options
context:
space:
mode:
authorJason van Zyl <jvanzyl@apache.org>2001-10-29 19:59:54 +0000
committerJason van Zyl <jvanzyl@apache.org>2001-10-29 19:59:54 +0000
commit96ac0670cf9944d4912ab25ec885a4bea651443d (patch)
tree485cb3c3d889d1e3db129b44e60f6714924314c7 /src/java/org/apache/bcel/verifier
parent32e0972903c55452f01defb3322dc0ce9ef0dd58 (diff)
downloadapache-commons-bcel-96ac0670cf9944d4912ab25ec885a4bea651443d.tar.gz
Initial revision
git-svn-id: https://svn.apache.org/repos/asf/jakarta/bcel/trunk@152690 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/bcel/verifier')
-rw-r--r--src/java/org/apache/bcel/verifier/GraphicalVerifier.java109
-rw-r--r--src/java/org/apache/bcel/verifier/NativeVerifier.java116
-rw-r--r--src/java/org/apache/bcel/verifier/PassVerifier.java143
-rw-r--r--src/java/org/apache/bcel/verifier/TransitiveHull.java138
-rw-r--r--src/java/org/apache/bcel/verifier/VerificationResult.java138
-rw-r--r--src/java/org/apache/bcel/verifier/Verifier.java283
-rw-r--r--src/java/org/apache/bcel/verifier/VerifierAppFrame.java390
-rw-r--r--src/java/org/apache/bcel/verifier/VerifierFactory.java142
-rw-r--r--src/java/org/apache/bcel/verifier/VerifierFactoryListModel.java107
-rw-r--r--src/java/org/apache/bcel/verifier/VerifierFactoryObserver.java76
-rw-r--r--src/java/org/apache/bcel/verifier/VerifyDialog.java559
-rw-r--r--src/java/org/apache/bcel/verifier/exc/AssertionViolatedException.java115
-rw-r--r--src/java/org/apache/bcel/verifier/exc/ClassConstraintException.java83
-rw-r--r--src/java/org/apache/bcel/verifier/exc/CodeConstraintException.java77
-rw-r--r--src/java/org/apache/bcel/verifier/exc/InvalidMethodException.java71
-rw-r--r--src/java/org/apache/bcel/verifier/exc/LinkingConstraintException.java74
-rw-r--r--src/java/org/apache/bcel/verifier/exc/LoadingException.java82
-rw-r--r--src/java/org/apache/bcel/verifier/exc/LocalVariableInfoInconsistentException.java81
-rw-r--r--src/java/org/apache/bcel/verifier/exc/StaticCodeConstraintException.java71
-rw-r--r--src/java/org/apache/bcel/verifier/exc/StaticCodeInstructionConstraintException.java74
-rw-r--r--src/java/org/apache/bcel/verifier/exc/StaticCodeInstructionOperandConstraintException.java74
-rw-r--r--src/java/org/apache/bcel/verifier/exc/StructuralCodeConstraintException.java82
-rw-r--r--src/java/org/apache/bcel/verifier/exc/Utility.java76
-rw-r--r--src/java/org/apache/bcel/verifier/exc/VerificationException.java82
-rw-r--r--src/java/org/apache/bcel/verifier/exc/VerifierConstraintViolatedException.java107
-rw-r--r--src/java/org/apache/bcel/verifier/exc/package.html24
-rw-r--r--src/java/org/apache/bcel/verifier/package.html25
-rw-r--r--src/java/org/apache/bcel/verifier/statics/DOUBLE_Upper.java79
-rw-r--r--src/java/org/apache/bcel/verifier/statics/IntList.java85
-rw-r--r--src/java/org/apache/bcel/verifier/statics/LONG_Upper.java79
-rw-r--r--src/java/org/apache/bcel/verifier/statics/LocalVariableInfo.java145
-rw-r--r--src/java/org/apache/bcel/verifier/statics/LocalVariablesInfo.java113
-rw-r--r--src/java/org/apache/bcel/verifier/statics/Pass1Verifier.java214
-rw-r--r--src/java/org/apache/bcel/verifier/statics/Pass2Verifier.java1334
-rw-r--r--src/java/org/apache/bcel/verifier/statics/Pass3aVerifier.java1070
-rw-r--r--src/java/org/apache/bcel/verifier/statics/StringRepresentation.java202
-rw-r--r--src/java/org/apache/bcel/verifier/statics/package.html26
-rw-r--r--src/java/org/apache/bcel/verifier/structurals/ControlFlowGraph.java466
-rw-r--r--src/java/org/apache/bcel/verifier/structurals/ExceptionHandler.java93
-rw-r--r--src/java/org/apache/bcel/verifier/structurals/ExceptionHandlers.java107
-rw-r--r--src/java/org/apache/bcel/verifier/structurals/ExecutionVisitor.java1126
-rw-r--r--src/java/org/apache/bcel/verifier/structurals/Frame.java153
-rw-r--r--src/java/org/apache/bcel/verifier/structurals/GenericArray.java66
-rw-r--r--src/java/org/apache/bcel/verifier/structurals/InstConstraintVisitor.java2652
-rw-r--r--src/java/org/apache/bcel/verifier/structurals/InstructionContext.java141
-rw-r--r--src/java/org/apache/bcel/verifier/structurals/LocalVariables.java229
-rw-r--r--src/java/org/apache/bcel/verifier/structurals/OperandStack.java275
-rw-r--r--src/java/org/apache/bcel/verifier/structurals/Pass3bVerifier.java366
-rw-r--r--src/java/org/apache/bcel/verifier/structurals/Subroutine.java126
-rw-r--r--src/java/org/apache/bcel/verifier/structurals/Subroutines.java668
-rw-r--r--src/java/org/apache/bcel/verifier/structurals/UninitializedObjectType.java97
-rw-r--r--src/java/org/apache/bcel/verifier/structurals/package.html27
52 files changed, 13338 insertions, 0 deletions
diff --git a/src/java/org/apache/bcel/verifier/GraphicalVerifier.java b/src/java/org/apache/bcel/verifier/GraphicalVerifier.java
new file mode 100644
index 00000000..e8f729ef
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/GraphicalVerifier.java
@@ -0,0 +1,109 @@
+package org.apache.bcel.verifier;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import javax.swing.UIManager;
+import java.awt.*;
+import org.apache.bcel.verifier.*;
+import org.apache.bcel.generic.*;
+
+
+/**
+ * A graphical user interface application demonstrating JustIce.
+ *
+ * @version $Id$
+ * @author Enver Haase
+ */
+public class GraphicalVerifier {
+ boolean packFrame = false;
+
+ /** Constructor. */
+ public GraphicalVerifier() {
+ VerifierAppFrame frame = new VerifierAppFrame();
+ //Frames überprüfen, die voreingestellte Größe haben
+ //Frames packen, die nutzbare bevorzugte Größeninformationen enthalten, z.B. aus ihrem Layout
+ if (packFrame) {
+ frame.pack();
+ }
+ else {
+ frame.validate();
+ }
+ //Das Fenster zentrieren
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ Dimension frameSize = frame.getSize();
+ if (frameSize.height > screenSize.height) {
+ frameSize.height = screenSize.height;
+ }
+ if (frameSize.width > screenSize.width) {
+ frameSize.width = screenSize.width;
+ }
+ frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
+ frame.setVisible(true);
+
+ frame.classNamesJList.setModel(new VerifierFactoryListModel());
+ VerifierFactory.getVerifier(Type.OBJECT.getClassName()); // Fill list with java.lang.Object
+ frame.classNamesJList.setSelectedIndex(0); // default, will verify java.lang.Object
+ }
+ /** Main method. */
+ public static void main(String[] args) {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ new GraphicalVerifier();
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/NativeVerifier.java b/src/java/org/apache/bcel/verifier/NativeVerifier.java
new file mode 100644
index 00000000..2e8bef41
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/NativeVerifier.java
@@ -0,0 +1,116 @@
+package org.apache.bcel.verifier;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/**
+ * The NativeVerifier class implements a main(String[] args) method that's
+ * roughly compatible to the one in the Verifier class, but that uses the
+ * JVM's internal verifier for its class file verification.
+ * This can be used for comparison runs between the JVM-internal verifier
+ * and JustIce.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public abstract class NativeVerifier{
+
+ /**
+ * This class must not be instantiated.
+ */
+ private NativeVerifier(){
+ }
+
+ /**
+ * Works only on the first argument.
+ */
+ public static void main(String [] args){
+ if (args.length != 1){
+ System.out.println("Verifier front-end: need exactly one argument.");
+ System.exit(1);
+ }
+
+ int dotclasspos = args[0].lastIndexOf(".class");
+ if (dotclasspos != -1) args[0] = args[0].substring(0,dotclasspos);
+ args[0] = args[0].replace('/','.');
+ //System.out.println(args[0]);
+
+
+ try{
+ Class.forName(args[0]);
+ }
+ catch(ExceptionInInitializerError eiie){ //subclass of LinkageError!
+ System.out.println("NativeVerifier: ExceptionInInitializerError encountered on '"+args[0]+"'.");
+ System.out.println(eiie);
+ System.exit(1);
+ }
+ catch(LinkageError le){
+ System.out.println("NativeVerifier: LinkageError encountered on '"+args[0]+"'.");
+ System.out.println(le);
+ System.exit(1);
+ }
+ catch(ClassNotFoundException cnfe){
+ System.out.println("NativeVerifier: FILE NOT FOUND: '"+args[0]+"'.");
+ System.exit(1);
+ }
+ catch(Throwable t){
+ System.out.println("NativeVerifier: Unspecified verification error on'"+args[0]+"'.");
+ System.exit(1);
+ }
+
+ System.out.println("NativeVerifier: Class file '"+args[0]+"' seems to be okay.");
+ System.exit(0);
+
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/PassVerifier.java b/src/java/org/apache/bcel/verifier/PassVerifier.java
new file mode 100644
index 00000000..6e35d857
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/PassVerifier.java
@@ -0,0 +1,143 @@
+package org.apache.bcel.verifier;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import java.util.ArrayList;
+
+/**
+ * A PassVerifier actually verifies a class file; it is instantiated
+ * by a Verifier.
+ * The verification should conform with a certain pass as described
+ * in The Java Virtual Machine Specification, 2nd edition.
+ * This book describes four passes. Pass one means loading the
+ * class and verifying a few static constraints. Pass two actually
+ * verifies some other constraints that could enforce loading in
+ * referenced class files. Pass three is the first pass that actually
+ * checks constraints in the code array of a method in the class file;
+ * it has two parts with the first verifying static constraints and
+ * the second part verifying structural constraints (where a data flow
+ * analysis is used for). The fourth pass, finally, performs checks
+ * that can only be done at run-time.
+ * JustIce does not have a run-time pass, but certain constraints that
+ * are usually delayed until run-time for performance reasons are also
+ * checked during the second part of pass three.
+ * PassVerifier instances perform caching.
+ * That means, if you really want a new verification run of a certain
+ * pass you must use a new instance of a given PassVerifier.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ * @see org.apache.bcel.verifier.Verifier
+ * @see #verify()
+ */
+public abstract class PassVerifier{
+
+ /** The (warning) messages. */
+ private ArrayList messages = new ArrayList(); //Type of elements: String
+
+ /** The VerificationResult cache. */
+ private VerificationResult verificationResult = null;
+
+ /**
+ * This method runs a verification pass conforming to the
+ * Java Virtual Machine Specification, 2nd edition, on a
+ * class file.
+ * PassVerifier instances perform caching;
+ * i.e. if the verify() method once determined a VerificationResult,
+ * then this result may be returned after every invocation of this
+ * method instead of running the verification pass anew; likewise with
+ * the result of getMessages().
+ *
+ * @see #getMessages()
+ * @see #addMessage(String)
+ */
+ public VerificationResult verify(){
+ if (verificationResult == null){
+ verificationResult = do_verify();
+ }
+ return verificationResult;
+ }
+
+ /** Does the real verification work, uncached. */
+ public abstract VerificationResult do_verify();
+
+ /**
+ * This method adds a (warning) message to the message pool of this
+ * PassVerifier. This method is normally only internally used by
+ * BCEL's class file verifier "JustIce" and should not be used from
+ * the outside.
+ *
+ * @see #getMessages()
+ */
+ public void addMessage(String message){
+ messages.add(message);
+ }
+
+ /**
+ * Returns the (warning) messages that this PassVerifier accumulated
+ * during its do_verify()ing work.
+ *
+ * @see #addMessage(String)
+ * @see #do_verify()
+ */
+ public String[] getMessages(){
+ verify(); // create messages if not already done (cached!)
+ String[] ret = new String[messages.size()];
+ for (int i=0; i<messages.size(); i++){
+ ret[i] = (String) messages.get(i);
+ }
+ return ret;
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/TransitiveHull.java b/src/java/org/apache/bcel/verifier/TransitiveHull.java
new file mode 100644
index 00000000..f450a4c2
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/TransitiveHull.java
@@ -0,0 +1,138 @@
+package org.apache.bcel.verifier;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.verifier.*;
+import org.apache.bcel.classfile.*;
+import org.apache.bcel.*;
+
+/**
+ * This class has a main method implementing a demonstration program
+ * of how to use the VerifierFactoryObserver. It transitively verifies
+ * all class files encountered; this may take up a lot of time and,
+ * more notably, memory.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class TransitiveHull implements VerifierFactoryObserver{
+
+ /** Used for indentation. */
+ private int indent = 0;
+
+ /** Not publicly instantiable. */
+ private TransitiveHull(){
+ }
+
+ /* Implementing VerifierFactoryObserver. */
+ public void update(String classname){
+
+ System.gc(); // avoid swapping if possible.
+
+ for (int i=0; i<indent; i++){
+ System.out.print(" ");
+ }
+ System.out.println(classname);
+ indent += 1;
+
+ Verifier v = VerifierFactory.getVerifier(classname);
+
+ VerificationResult vr;
+ vr = v.doPass1();
+ if (vr != VerificationResult.VR_OK) //System.exit(1);
+ System.out.println("Pass 1:\n"+vr);
+
+ vr = v.doPass2();
+ if (vr != VerificationResult.VR_OK) //System.exit(1);
+ System.out.println("Pass 2:\n"+vr);
+
+ if (vr == VerificationResult.VR_OK){
+ JavaClass jc = Repository.lookupClass(v.getClassName());
+ for (int i=0; i<jc.getMethods().length; i++){
+ vr = v.doPass3a(i);
+ if (vr != VerificationResult.VR_OK) //System.exit(1);
+ System.out.println(v.getClassName()+", Pass 3a, method "+i+" ['"+jc.getMethods()[i]+"']:\n"+vr);
+
+ vr = v.doPass3b(i);
+ if (vr != VerificationResult.VR_OK) //System.exit(1);
+ System.out.println(v.getClassName()+", Pass 3b, method "+i+" ['"+jc.getMethods()[i]+"']:\n"+vr);
+ }
+ }
+
+ indent -= 1;
+ }
+
+ /**
+ * This method implements a demonstration program
+ * of how to use the VerifierFactoryObserver. It transitively verifies
+ * all class files encountered; this may take up a lot of time and,
+ * more notably, memory.
+ */
+ public static void main(String[] args){
+ if (args.length != 1){
+ System.out.println("Need exactly one argument: The root class to verify.");
+ System.exit(1);
+ }
+
+ int dotclasspos = args[0].lastIndexOf(".class");
+ if (dotclasspos != -1) args[0] = args[0].substring(0,dotclasspos);
+ args[0] = args[0].replace('/', '.');
+
+ TransitiveHull th = new TransitiveHull();
+ VerifierFactory.attach(th);
+ VerifierFactory.getVerifier(args[0]); // the observer is called back and does the actual trick.
+ VerifierFactory.detach(th);
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/VerificationResult.java b/src/java/org/apache/bcel/verifier/VerificationResult.java
new file mode 100644
index 00000000..b296e1f6
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/VerificationResult.java
@@ -0,0 +1,138 @@
+package org.apache.bcel.verifier;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/**
+ * A VerificationResult is what a PassVerifier returns
+ * after verifying.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ *
+ */
+public class VerificationResult{
+
+ /**
+ * Constant to indicate verification has not been tried yet.
+ * This happens if some earlier verification pass did not return VERIFIED_OK.
+ */
+ public static final int VERIFIED_NOTYET = 0;
+ /** Constant to indicate verification was passed. */
+ public static final int VERIFIED_OK = 1;
+ /** Constant to indicate verfication failed. */
+ public static final int VERIFIED_REJECTED = 2;
+
+ /**
+ * This string is the canonical message for verifications that have not been tried yet.
+ * This happens if some earlier verification pass did not return VERIFIED_OK.
+ */
+ private static final String VERIFIED_NOTYET_MSG = "Not yet verified.";
+ /** This string is the canonical message for passed verification passes. */
+ private static final String VERIFIED_OK_MSG = "Passed verification.";
+
+ /**
+ * Canonical VerificationResult for not-yet-tried verifications.
+ * This happens if some earlier verification pass did not return VERIFIED_OK.
+ */
+ public static final VerificationResult VR_NOTYET = new VerificationResult(VERIFIED_NOTYET, VERIFIED_NOTYET_MSG);
+ /** Canonical VerificationResult for passed verifications. */
+ public static final VerificationResult VR_OK = new VerificationResult(VERIFIED_OK, VERIFIED_OK_MSG);
+
+ /** The numeric status. */
+ private int numeric;
+
+ /** The detailed message. */
+ private String detailMessage;
+
+ /** This class is not no-args instantiable. */
+ private VerificationResult(){}
+
+ /** The usual constructor. */
+ public VerificationResult(int status, String message){
+ numeric = status;
+ detailMessage = message;
+ }
+
+ /** Returns one one the VERIFIED_OK, VERIFIED_NOTYET, VERIFIED_REJECTED constants. */
+ public int getStatus(){
+ return numeric;
+ }
+
+ /** Returns a detailed message. */
+ public String getMessage(){
+ return detailMessage;
+ }
+
+ /**
+ * Returns if two VerificationResult instances are equal.
+ */
+ public boolean equals(Object o){
+ if (! (o instanceof VerificationResult)) return false;
+ VerificationResult other = (VerificationResult) o;
+ return ((other.numeric == this.numeric) && (other.detailMessage.equals(this.detailMessage)));
+ }
+
+ /**
+ * Returns a String representation of the VerificationResult.
+ */
+ public String toString(){
+ String ret="";
+ if (numeric == VERIFIED_NOTYET) ret = "VERIFIED_NOTYET";
+ if (numeric == VERIFIED_OK) ret = "VERIFIED_OK";
+ if (numeric == VERIFIED_REJECTED) ret = "VERIFIED_REJECTED";
+ ret+="\n"+detailMessage+"\n";
+ return ret;
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/Verifier.java b/src/java/org/apache/bcel/verifier/Verifier.java
new file mode 100644
index 00000000..8e2dd2b8
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/Verifier.java
@@ -0,0 +1,283 @@
+package org.apache.bcel.verifier;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.*;
+import org.apache.bcel.classfile.*;
+import org.apache.bcel.generic.*;
+import org.apache.bcel.util.*;
+import org.apache.bcel.verifier.statics.*;
+import org.apache.bcel.verifier.structurals.*;
+import org.apache.bcel.verifier.exc.*;
+import org.apache.bcel.verifier.exc.Utility; // Ambigous if not declared explicitely.
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * A Verifier instance is there to verify a class file according to The Java Virtual
+ * Machine Specification, 2nd Edition.
+ *
+ * Pass-3b-verification includes pass-3a-verification;
+ * pass-3a-verification includes pass-2-verification;
+ * pass-2-verification includes pass-1-verification.
+ *
+ * A Verifier creates PassVerifier instances to perform the actual verification.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ * @see org.apache.bcel.verifier.PassVerifier
+ */
+public class Verifier{
+ /**
+ * The name of the class this verifier operates on.
+ */
+ private final String classname;
+
+ /** A Pass1Verifier for this Verifier instance. */
+ private Pass1Verifier p1v;
+ /** A Pass2Verifier for this Verifier instance. */
+ private Pass2Verifier p2v;
+ /** The Pass3aVerifiers for this Verifier instance. Key: Interned string specifying the method number. */
+ private HashMap p3avs = new HashMap();
+ /** The Pass3bVerifiers for this Verifier instance. Key: Interned string specifying the method number. */
+ private HashMap p3bvs = new HashMap();
+
+ /** Returns the VerificationResult for the given pass. */
+ public VerificationResult doPass1(){
+ if (p1v == null){
+ p1v = new Pass1Verifier(this);
+ }
+ return p1v.verify();
+ }
+
+ /** Returns the VerificationResult for the given pass. */
+ public VerificationResult doPass2(){
+ if (p2v == null){
+ p2v = new Pass2Verifier(this);
+ }
+ return p2v.verify();
+ }
+
+ /** Returns the VerificationResult for the given pass. */
+ public VerificationResult doPass3a(int method_no){
+ String key = Integer.toString(method_no);
+ Pass3aVerifier p3av;
+ p3av = (Pass3aVerifier) (p3avs.get(key));
+ if (p3avs.get(key) == null){
+ p3av = new Pass3aVerifier(this, method_no);
+ p3avs.put(key, p3av);
+ }
+ return p3av.verify();
+ }
+
+ /** Returns the VerificationResult for the given pass. */
+ public VerificationResult doPass3b(int method_no){
+ String key = Integer.toString(method_no);
+ Pass3bVerifier p3bv;
+ p3bv = (Pass3bVerifier) (p3bvs.get(key));
+ if (p3bvs.get(key) == null){
+ p3bv = new Pass3bVerifier(this, method_no);
+ p3bvs.put(key, p3bv);
+ }
+ return p3bv.verify();
+ }
+
+ /**
+ * This class may not be no-args instantiated.
+ */
+ private Verifier(){
+ classname = ""; // never executed anyway, make compiler happy.
+ }// not noargs-instantiable
+
+ /**
+ * Instantiation is done by the VerifierFactory.
+ *
+ * @see VerifierFactory
+ */
+ Verifier(String fully_qualified_classname){
+ classname = fully_qualified_classname;
+ flush();
+ }
+
+ /**
+ * Returns the name of the class this verifier operates on.
+ * This is particularly interesting when this verifier was created
+ * recursively by another Verifier and you got a reference to this
+ * Verifier by the getVerifiers() method of the VerifierFactory.
+ * @see VerifierFactory
+ */
+ public final String getClassName(){
+ return classname;
+ }
+
+ /**
+ * Forget everything known about the class file; that means, really
+ * start a new verification of a possibly different class file from
+ * BCEL's repository.
+ *
+ */
+ public void flush(){
+ p1v = null;
+ p2v = null;
+ p3avs.clear();
+ p3bvs.clear();
+ }
+
+ /**
+ * This returns all the (warning) messages collected during verification.
+ * A prefix shows from which verifying pass a message originates.
+ */
+ public String[] getMessages(){
+ ArrayList messages = new ArrayList();
+
+ if (p1v != null){
+ String[] p1m = p1v.getMessages();
+ for (int i=0; i<p1m.length; i++){
+ messages.add("Pass 1: "+p1m[i]);
+ }
+ }
+ if (p2v != null){
+ String[] p2m = p2v.getMessages();
+ for (int i=0; i<p2m.length; i++){
+ messages.add("Pass 2: "+p2m[i]);
+ }
+ }
+ Iterator p3as = p3avs.values().iterator();
+ while (p3as.hasNext()){
+ Pass3aVerifier pv = (Pass3aVerifier) p3as.next();
+ String[] p3am = pv.getMessages();
+ int meth = pv.getMethodNo();
+ for (int i=0; i<p3am.length; i++){
+ messages.add("Pass 3a, method "+meth+" ('"+Repository.lookupClass(classname).getMethods()[meth]+"'): "+p3am[i]);
+ }
+ }
+ Iterator p3bs = p3bvs.values().iterator();
+ while (p3bs.hasNext()){
+ Pass3bVerifier pv = (Pass3bVerifier) p3bs.next();
+ String[] p3bm = pv.getMessages();
+ int meth = pv.getMethodNo();
+ for (int i=0; i<p3bm.length; i++){
+ messages.add("Pass 3b, method "+meth+" ('"+Repository.lookupClass(classname).getMethods()[meth]+"'): "+p3bm[i]);
+ }
+ }
+
+ String[] ret = new String[messages.size()];
+ for (int i=0; i< messages.size(); i++){
+ ret[i] = (String) messages.get(i);
+ }
+
+ return ret;
+ }
+
+ /**
+ * Verifies class files.
+ * This is a simple demonstration of how the API of BCEL's
+ * class file verifier "JustIce" may be used.
+ * You should supply command-line arguments which are
+ * fully qualified namea of the classes to verify. These class files
+ * must be somewhere in your CLASSPATH (refer to Sun's
+ * documentation for questions about this) or you must have put the classes
+ * into the BCEL Repository yourself (via 'addClass(JavaClass)').
+ */
+ public static void main(String [] args){
+ System.out.println("JustIce by Enver Haase, (C) 2001. http://bcel.sourceforge.net\n");
+ for(int k=0; k < args.length; k++) {
+
+ if (args[k].endsWith(".class")){
+ int dotclasspos = args[k].lastIndexOf(".class");
+ if (dotclasspos != -1) args[k] = args[k].substring(0,dotclasspos);
+ }
+
+ args[k] = args[k].replace('/', '.');
+
+ System.out.println("Now verifiying: "+args[k]+"\n");
+
+ Verifier v = VerifierFactory.getVerifier(args[k]);
+ VerificationResult vr;
+
+ vr = v.doPass1();
+ System.out.println("Pass 1:\n"+vr);
+
+ vr = v.doPass2();
+ System.out.println("Pass 2:\n"+vr);
+
+ if (vr == VerificationResult.VR_OK){
+ JavaClass jc = Repository.lookupClass(args[k]);
+ for (int i=0; i<jc.getMethods().length; i++){
+ vr = v.doPass3a(i);
+ System.out.println("Pass 3a, method "+i+" ['"+jc.getMethods()[i]+"']:\n"+vr);
+
+ vr = v.doPass3b(i);
+ System.out.println("Pass 3b, method number "+i+" ['"+jc.getMethods()[i]+"']:\n"+vr);
+ }
+ }
+
+ System.out.println("Warnings:");
+ String[] warnings = v.getMessages();
+ if (warnings.length == 0) System.out.println("<none>");
+ for (int j=0; j<warnings.length; j++){
+ System.out.println(warnings[j]);
+ }
+
+ System.out.println("\n");
+
+ // avoid swapping.
+ v.flush();
+ Repository.clearCache();
+ System.gc();
+ }
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/VerifierAppFrame.java b/src/java/org/apache/bcel/verifier/VerifierAppFrame.java
new file mode 100644
index 00000000..4d5e9842
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/VerifierAppFrame.java
@@ -0,0 +1,390 @@
+package org.apache.bcel.verifier;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.apache.bcel.*;
+import org.apache.bcel.classfile.*;
+import org.apache.bcel.verifier.*;
+
+/**
+ * This class implements a machine-generated frame for use with
+ * the GraphicalVerfifier.
+ *
+ * @version $Id$
+ * @author Enver Haase
+ * @see GraphicalVerifier
+ */
+public class VerifierAppFrame extends JFrame {
+ JPanel contentPane;
+ JSplitPane jSplitPane1 = new JSplitPane();
+ JPanel jPanel1 = new JPanel();
+ JPanel jPanel2 = new JPanel();
+ JSplitPane jSplitPane2 = new JSplitPane();
+ JPanel jPanel3 = new JPanel();
+ JList classNamesJList = new JList();
+ GridLayout gridLayout1 = new GridLayout();
+ JPanel messagesPanel = new JPanel();
+ GridLayout gridLayout2 = new GridLayout();
+ JMenuBar jMenuBar1 = new JMenuBar();
+ JMenu jMenu1 = new JMenu();
+ JScrollPane jScrollPane1 = new JScrollPane();
+ JScrollPane messagesScrollPane = new JScrollPane();
+ JScrollPane jScrollPane3 = new JScrollPane();
+ GridLayout gridLayout4 = new GridLayout();
+ JScrollPane jScrollPane4 = new JScrollPane();
+ CardLayout cardLayout1 = new CardLayout();
+
+ private String JUSTICE_VERSION = "JustIce by Enver Haase";
+ private String current_class;
+ GridLayout gridLayout3 = new GridLayout();
+ JTextPane pass1TextPane = new JTextPane();
+ JTextPane pass2TextPane = new JTextPane();
+ JTextPane messagesTextPane = new JTextPane();
+ JMenuItem newFileMenuItem = new JMenuItem();
+ JSplitPane jSplitPane3 = new JSplitPane();
+ JSplitPane jSplitPane4 = new JSplitPane();
+ JScrollPane jScrollPane2 = new JScrollPane();
+ JScrollPane jScrollPane5 = new JScrollPane();
+ JScrollPane jScrollPane6 = new JScrollPane();
+ JScrollPane jScrollPane7 = new JScrollPane();
+ JList pass3aJList = new JList();
+ JList pass3bJList = new JList();
+ JTextPane pass3aTextPane = new JTextPane();
+ JTextPane pass3bTextPane = new JTextPane();
+ JMenu jMenu2 = new JMenu();
+ JMenuItem whatisMenuItem = new JMenuItem();
+ JMenuItem aboutMenuItem = new JMenuItem();
+
+ /** Constructor. */
+ public VerifierAppFrame() {
+ enableEvents(AWTEvent.WINDOW_EVENT_MASK);
+ try {
+ jbInit();
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+ /** Initizalization of the components. */
+ private void jbInit() throws Exception {
+ //setIconImage(Toolkit.getDefaultToolkit().createImage(Frame1.class.getResource("[Ihr Symbol]")));
+ contentPane = (JPanel) this.getContentPane();
+ contentPane.setLayout(cardLayout1);
+ this.setJMenuBar(jMenuBar1);
+ this.setSize(new Dimension(708, 451));
+ this.setTitle("JustIce");
+ jPanel1.setMinimumSize(new Dimension(100, 100));
+ jPanel1.setPreferredSize(new Dimension(100, 100));
+ jPanel1.setLayout(gridLayout1);
+ jSplitPane2.setOrientation(JSplitPane.VERTICAL_SPLIT);
+ jPanel2.setLayout(gridLayout2);
+ jPanel3.setMinimumSize(new Dimension(200, 100));
+ jPanel3.setPreferredSize(new Dimension(400, 400));
+ jPanel3.setLayout(gridLayout4);
+ messagesPanel.setMinimumSize(new Dimension(100, 100));
+ messagesPanel.setLayout(gridLayout3);
+ jPanel2.setMinimumSize(new Dimension(200, 100));
+ jMenu1.setText("File");
+
+ jScrollPane1.getViewport().setBackground(Color.red);
+ messagesScrollPane.getViewport().setBackground(Color.red);
+ messagesScrollPane.setPreferredSize(new Dimension(10, 10));
+ classNamesJList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
+ public void valueChanged(ListSelectionEvent e) {
+ classNamesJList_valueChanged(e);
+ }
+ });
+ classNamesJList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ jScrollPane3.setBorder(BorderFactory.createLineBorder(Color.black));
+ jScrollPane3.setPreferredSize(new Dimension(100, 100));
+ gridLayout4.setRows(4);
+ gridLayout4.setColumns(1);
+ gridLayout4.setHgap(1);
+ jScrollPane4.setBorder(BorderFactory.createLineBorder(Color.black));
+ jScrollPane4.setPreferredSize(new Dimension(100, 100));
+ pass1TextPane.setBorder(BorderFactory.createRaisedBevelBorder());
+ pass1TextPane.setToolTipText("");
+ pass1TextPane.setEditable(false);
+ pass2TextPane.setBorder(BorderFactory.createRaisedBevelBorder());
+ pass2TextPane.setEditable(false);
+ messagesTextPane.setBorder(BorderFactory.createRaisedBevelBorder());
+ messagesTextPane.setEditable(false);
+ newFileMenuItem.setText("New...");
+ newFileMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(78, java.awt.event.KeyEvent.CTRL_MASK, true));
+ newFileMenuItem.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ newFileMenuItem_actionPerformed(e);
+ }
+ });
+ pass3aTextPane.setEditable(false);
+ pass3bTextPane.setEditable(false);
+ pass3aJList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
+ public void valueChanged(ListSelectionEvent e) {
+ pass3aJList_valueChanged(e);
+ }
+ });
+ pass3bJList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
+ public void valueChanged(ListSelectionEvent e) {
+ pass3bJList_valueChanged(e);
+ }
+ });
+ jMenu2.setText("Help");
+ whatisMenuItem.setText("What is...");
+ whatisMenuItem.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ whatisMenuItem_actionPerformed(e);
+ }
+ });
+ aboutMenuItem.setText("About");
+ aboutMenuItem.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ aboutMenuItem_actionPerformed(e);
+ }
+ });
+ jSplitPane2.add(messagesPanel, JSplitPane.BOTTOM);
+ messagesPanel.add(messagesScrollPane, null);
+ messagesScrollPane.getViewport().add(messagesTextPane, null);
+ jSplitPane2.add(jPanel3, JSplitPane.TOP);
+ jPanel3.add(jScrollPane3, null);
+ jScrollPane3.getViewport().add(pass1TextPane, null);
+ jPanel3.add(jScrollPane4, null);
+ jPanel3.add(jSplitPane3, null);
+ jSplitPane3.add(jScrollPane2, JSplitPane.LEFT);
+ jScrollPane2.getViewport().add(pass3aJList, null);
+ jSplitPane3.add(jScrollPane5, JSplitPane.RIGHT);
+ jScrollPane5.getViewport().add(pass3aTextPane, null);
+ jPanel3.add(jSplitPane4, null);
+ jSplitPane4.add(jScrollPane6, JSplitPane.LEFT);
+ jScrollPane6.getViewport().add(pass3bJList, null);
+ jSplitPane4.add(jScrollPane7, JSplitPane.RIGHT);
+ jScrollPane7.getViewport().add(pass3bTextPane, null);
+ jScrollPane4.getViewport().add(pass2TextPane, null);
+ jSplitPane1.add(jPanel2, JSplitPane.TOP);
+ jPanel2.add(jScrollPane1, null);
+ jSplitPane1.add(jPanel1, JSplitPane.BOTTOM);
+ jPanel1.add(jSplitPane2, null);
+ jScrollPane1.getViewport().add(classNamesJList, null);
+ jMenuBar1.add(jMenu1);
+ jMenuBar1.add(jMenu2);
+ contentPane.add(jSplitPane1, "jSplitPane1");
+ jMenu1.add(newFileMenuItem);
+ jMenu2.add(whatisMenuItem);
+ jMenu2.add(aboutMenuItem);
+ jSplitPane2.setDividerLocation(300);
+ jSplitPane3.setDividerLocation(150);
+ jSplitPane4.setDividerLocation(150);
+ }
+
+ /** Overridden to stop the application on a closing window. */
+ protected void processWindowEvent(WindowEvent e) {
+ super.processWindowEvent(e);
+ if (e.getID() == WindowEvent.WINDOW_CLOSING) {
+ System.exit(0);
+ }
+ }
+
+ synchronized void classNamesJList_valueChanged(ListSelectionEvent e) {
+ if (e.getValueIsAdjusting()) return;
+ current_class = classNamesJList.getSelectedValue().toString();
+ verify();
+ classNamesJList.setSelectedValue(current_class, true);
+ }
+
+ private void verify(){
+ setTitle("PLEASE WAIT");
+
+ Verifier v = VerifierFactory.getVerifier(current_class);
+ v.flush(); // Don't cache the verification result for this class.
+
+ VerificationResult vr;
+
+ vr = v.doPass1();
+ if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED){
+ pass1TextPane.setText(vr.getMessage());
+ pass1TextPane.setBackground(Color.red);
+
+ pass2TextPane.setText("");
+ pass2TextPane.setBackground(Color.yellow);
+ pass3aTextPane.setText("");
+ pass3aJList.setListData(new Object[0]);
+ pass3aTextPane.setBackground(Color.yellow);
+
+ pass3bTextPane.setText("");
+ pass3bJList.setListData(new Object[0]);
+ pass3bTextPane.setBackground(Color.yellow);
+
+ }
+ else{ // Must be VERIFIED_OK, Pass 1 does not know VERIFIED_NOTYET
+ pass1TextPane.setBackground(Color.green);
+ pass1TextPane.setText(vr.getMessage());
+
+ vr = v.doPass2();
+ if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED){
+ pass2TextPane.setText(vr.getMessage());
+ pass2TextPane.setBackground(Color.red);
+
+ pass3aTextPane.setText("");
+ pass3aTextPane.setBackground(Color.yellow);
+ pass3aJList.setListData(new Object[0]);
+ pass3bTextPane.setText("");
+ pass3bTextPane.setBackground(Color.yellow);
+ pass3bJList.setListData(new Object[0]);
+ }
+ else{ // must be Verified_OK, because Pass1 was OK (cannot be Verified_NOTYET).
+ pass2TextPane.setText(vr.getMessage());
+ pass2TextPane.setBackground(Color.green);
+
+ JavaClass jc = Repository.lookupClass(current_class);
+ boolean all3aok = true;
+ boolean all3bok = true;
+ String all3amsg = "";
+ String all3bmsg = "";
+
+ String[] methodnames = new String[jc.getMethods().length];
+ for (int i=0; i<jc.getMethods().length; i++){
+ methodnames[i] = jc.getMethods()[i].toString().replace('\n',' ').replace('\t',' ');
+ }
+ pass3aJList.setListData(methodnames);
+ pass3aJList.setSelectionInterval(0,jc.getMethods().length-1);
+ pass3bJList.setListData(methodnames);
+ pass3bJList.setSelectionInterval(0,jc.getMethods().length-1);
+ }
+
+ }
+ String[] msgs = v.getMessages();
+ messagesTextPane.setBackground(msgs.length == 0? Color.green : Color.yellow);
+ String allmsgs = "";
+ for (int i=0; i<msgs.length; i++){
+ msgs[i] = msgs[i].replace('\n',' ');
+ allmsgs += msgs[i] + "\n\n";
+ }
+ messagesTextPane.setText(allmsgs);
+
+ setTitle(current_class + " - " + JUSTICE_VERSION);
+ }
+
+ void newFileMenuItem_actionPerformed(ActionEvent e) {
+ String classname = JOptionPane.showInputDialog("Please enter the fully qualified name of a class or interface to verify:");
+ if ((classname == null) || (classname.equals(""))) return;
+ VerifierFactory.getVerifier(classname); // let observers do the rest.
+ classNamesJList.setSelectedValue(classname, true);
+ }
+
+ synchronized void pass3aJList_valueChanged(ListSelectionEvent e) {
+
+ if (e.getValueIsAdjusting()) return;
+ Verifier v = VerifierFactory.getVerifier(current_class);
+
+ String all3amsg = "";
+ boolean all3aok = true;
+ boolean rejected = false;
+ for (int i=0; i<pass3aJList.getModel().getSize(); i++){
+
+ if (pass3aJList.isSelectedIndex(i)){
+ VerificationResult vr = v.doPass3a(i);
+
+ if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED){
+ all3aok = false;
+ rejected = true;
+ }
+ all3amsg += "Method '"+Repository.lookupClass(v.getClassName()).getMethods()[i]+"': "+vr.getMessage().replace('\n',' ')+"\n\n";
+ }
+ }
+ pass3aTextPane.setText(all3amsg);
+ pass3aTextPane.setBackground(all3aok? Color.green : (rejected? Color.red : Color.yellow));
+
+ }
+
+ synchronized void pass3bJList_valueChanged(ListSelectionEvent e) {
+ if (e.getValueIsAdjusting()) return;
+
+ Verifier v = VerifierFactory.getVerifier(current_class);
+
+ String all3bmsg = "";
+ boolean all3bok = true;
+ boolean rejected = false;
+ for (int i=0; i<pass3bJList.getModel().getSize(); i++){
+
+ if (pass3bJList.isSelectedIndex(i)){
+ VerificationResult vr = v.doPass3b(i);
+
+ if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED){
+ all3bok = false;
+ rejected = true;
+ }
+ all3bmsg += "Method '"+Repository.lookupClass(v.getClassName()).getMethods()[i]+"': "+vr.getMessage().replace('\n',' ')+"\n\n";
+ }
+ }
+ pass3bTextPane.setText(all3bmsg);
+ pass3bTextPane.setBackground(all3bok? Color.green : (rejected? Color.red : Color.yellow));
+
+ }
+
+ void aboutMenuItem_actionPerformed(ActionEvent e) {
+ JOptionPane.showMessageDialog(this,
+ "JustIce is a Java class file verifier.\nIt was implemented by Enver Haase in 2001.\nhttp://bcel.sourceforge.net",
+ JUSTICE_VERSION, JOptionPane.INFORMATION_MESSAGE);
+ }
+
+ void whatisMenuItem_actionPerformed(ActionEvent e) {
+ JOptionPane.showMessageDialog(this,
+ "The upper four boxes to the right reflect verification passes according to The Java Virtual Machine Specification.\nThese are (in that order): Pass one, Pass two, Pass three (before data flow analysis), Pass three (data flow analysis).\nThe bottom box to the right shows (warning) messages; warnings do not cause a class to be rejected.",
+ JUSTICE_VERSION, JOptionPane.INFORMATION_MESSAGE);
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/VerifierFactory.java b/src/java/org/apache/bcel/verifier/VerifierFactory.java
new file mode 100644
index 00000000..c6ff992b
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/VerifierFactory.java
@@ -0,0 +1,142 @@
+package org.apache.bcel.verifier;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Vector;
+
+/**
+ * This class produces instances of the Verifier class. Its purpose is to make
+ * sure that they are singleton instances with respect to the class name they
+ * operate on. That means, for every class (represented by a unique fully qualified
+ * class name) there is exactly one Verifier.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class VerifierFactory{
+
+ /**
+ * The HashMap that holds the data about the already-constructed Verifier instances.
+ */
+ private static HashMap hashMap = new HashMap();
+
+ /**
+ * The VerifierFactoryObserver instances that observe the VerifierFactory.
+ */
+ private static Vector observers = new Vector();
+
+ /**
+ * The VerifierFactory is not instantiable.
+ */
+ private VerifierFactory(){}
+
+ /**
+ * Returns the (only) verifier responsible for the class with the given name.
+ * Possibly a new Verifier object is transparently created.
+ * @return the (only) verifier responsible for the class with the given name.
+ */
+ public static Verifier getVerifier(String fully_qualified_classname){
+ fully_qualified_classname = fully_qualified_classname;
+
+ Verifier v = (Verifier) (hashMap.get(fully_qualified_classname));
+ if (v==null){
+ v = new Verifier(fully_qualified_classname);
+ hashMap.put(fully_qualified_classname, v);
+ notify(fully_qualified_classname);
+ }
+
+ return v;
+ }
+
+ /**
+ * Notifies the observers of a newly generated Verifier.
+ */
+ private static void notify(String fully_qualified_classname){
+ // notify the observers
+ Iterator i = observers.iterator();
+ while (i.hasNext()){
+ VerifierFactoryObserver vfo = (VerifierFactoryObserver) i.next();
+ vfo.update(fully_qualified_classname);
+ }
+ }
+
+ /**
+ * Returns all Verifier instances created so far.
+ * This is useful when a Verifier recursively lets
+ * the VerifierFactory create other Verifier instances
+ * and if you want to verify the transitive hull of
+ * referenced class files.
+ */
+ public static Verifier[] getVerifiers(){
+ Verifier[] vs = new Verifier[hashMap.values().size()];
+ return (Verifier[]) (hashMap.values().toArray(vs)); // Because vs is big enough, vs is used to store the values into and returned!
+ }
+
+ /**
+ * Adds the VerifierFactoryObserver o to the list of observers.
+ */
+ public static void attach(VerifierFactoryObserver o){
+ observers.addElement(o);
+ }
+
+ /**
+ * Removes the VerifierFactoryObserver o from the list of observers.
+ */
+ public static void detach(VerifierFactoryObserver o){
+ observers.removeElement(o);
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/VerifierFactoryListModel.java b/src/java/org/apache/bcel/verifier/VerifierFactoryListModel.java
new file mode 100644
index 00000000..38d4cd05
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/VerifierFactoryListModel.java
@@ -0,0 +1,107 @@
+package org.apache.bcel.verifier;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+import org.apache.bcel.verifier.*;
+import javax.swing.event.*;
+/**
+ * This class implements an adapter; it implements both a Swing ListModel and
+ * a VerifierFactoryObserver.
+ *
+ * @version $Id$
+ * @author Enver Haase
+ */
+public class VerifierFactoryListModel implements org.apache.bcel.verifier.VerifierFactoryObserver, javax.swing.ListModel{
+
+ private java.util.ArrayList listeners = new java.util.ArrayList();
+
+ private java.util.TreeSet cache = new java.util.TreeSet();
+
+ public VerifierFactoryListModel() {
+ VerifierFactory.attach(this);
+ update(null); // fill cache.
+ }
+
+ public synchronized void update(String s){
+ int size = listeners.size();
+
+ Verifier[] verifiers = VerifierFactory.getVerifiers();
+ int num_of_verifiers = verifiers.length;
+ cache.clear();
+ for (int i=0; i<num_of_verifiers; i++) {
+ cache.add(verifiers[i].getClassName());
+ }
+
+ for (int i=0; i<size; i++){
+ ListDataEvent e = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, num_of_verifiers-1);
+ ((javax.swing.event.ListDataListener) (listeners.get(i))).contentsChanged(e);
+ }
+ }
+
+ public synchronized void addListDataListener(javax.swing.event.ListDataListener l){
+ listeners.add(l);
+ }
+
+ public synchronized void removeListDataListener(javax.swing.event.ListDataListener l){
+ listeners.remove(l);
+ }
+
+ public synchronized int getSize(){
+ return cache.size();
+ }
+
+ public synchronized Object getElementAt(int index){
+ return (cache.toArray())[index];
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/VerifierFactoryObserver.java b/src/java/org/apache/bcel/verifier/VerifierFactoryObserver.java
new file mode 100644
index 00000000..0d0480f6
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/VerifierFactoryObserver.java
@@ -0,0 +1,76 @@
+package org.apache.bcel.verifier;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/**
+ * VerifierFactoryObserver instances are notified when new Verifier
+ * instances are created.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ *
+ * @see VerifierFactory#getVerifier(String)
+ * @see VerifierFactory#getVerifiers()
+ * @see VerifierFactory#attach(VerifierFactoryObserver)
+ * @see VerifierFactory#detach(VerifierFactoryObserver)
+ */
+public interface VerifierFactoryObserver{
+ /**
+ * VerifierFactoryObserver instances are notified invoking this method.
+ * The String argument is the fully qualified class name of a class a
+ * new Verifier instance created by the VerifierFactory operates on.
+ */
+ public void update(String s);
+}
diff --git a/src/java/org/apache/bcel/verifier/VerifyDialog.java b/src/java/org/apache/bcel/verifier/VerifyDialog.java
new file mode 100644
index 00000000..9fe642d0
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/VerifyDialog.java
@@ -0,0 +1,559 @@
+package org.apache.bcel.verifier;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.*;
+import org.apache.bcel.classfile.*;
+import org.apache.bcel.verifier.*;
+import java.awt.Color;
+
+/**
+ * A class for simple graphical class file verification.
+ * Use the main(String []) method with fully qualified
+ * class names as arguments to use it as a stand-alone
+ * application.
+ * Use the VerifyDialog(String) constructor to use this
+ * class in your application.
+ * [This class was created using VisualAge for Java,
+ * but it does not work under VAJ itself (Version 3.02 JDK 1.2)]
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ * @see #main(String[])
+ * @see #VerifyDialog(String)
+ */
+public class VerifyDialog extends javax.swing.JDialog {
+ /** Machine-generated. */
+ private javax.swing.JPanel ivjJDialogContentPane = null;
+ /** Machine-generated. */
+ private javax.swing.JPanel ivjPass1Panel = null;
+ /** Machine-generated. */
+ private javax.swing.JPanel ivjPass2Panel = null;
+ /** Machine-generated. */
+ private javax.swing.JPanel ivjPass3Panel = null;
+ /** Machine-generated. */
+ private javax.swing.JButton ivjPass1Button = null;
+ /** Machine-generated. */
+ private javax.swing.JButton ivjPass2Button = null;
+ /** Machine-generated. */
+ private javax.swing.JButton ivjPass3Button = null;
+ /** Machine-generated. */
+ IvjEventHandler ivjEventHandler = new IvjEventHandler();
+
+ /**
+ * The class to verify. Default set to 'java.lang.Object'
+ * in case this class is instantiated via one of the many
+ * machine-generated constructors.
+ */
+ private String class_name = "java.lang.Object";
+
+ /**
+ * This field is here to count the number of open VerifyDialog
+ * instances so the JVM can be exited afer every Dialog had been
+ * closed.
+ */
+ private static int classes_to_verify;
+
+/** Machine-generated. */
+class IvjEventHandler implements java.awt.event.ActionListener {
+ public void actionPerformed(java.awt.event.ActionEvent e) {
+ if (e.getSource() == VerifyDialog.this.getPass1Button())
+ connEtoC1(e);
+ if (e.getSource() == VerifyDialog.this.getPass2Button())
+ connEtoC2(e);
+ if (e.getSource() == VerifyDialog.this.getPass3Button())
+ connEtoC3(e);
+ if (e.getSource() == VerifyDialog.this.getFlushButton())
+ connEtoC4(e);
+ };
+ };
+ /** Machine-generated. */
+ private javax.swing.JButton ivjFlushButton = null;
+/** Machine-generated. */
+public VerifyDialog() {
+ super();
+ initialize();
+}
+
+/** Machine-generated. */
+public VerifyDialog(java.awt.Dialog owner) {
+ super(owner);
+}
+
+/** Machine-generated. */
+public VerifyDialog(java.awt.Dialog owner, String title) {
+ super(owner, title);
+}
+
+/** Machine-generated. */
+public VerifyDialog(java.awt.Dialog owner, String title, boolean modal) {
+ super(owner, title, modal);
+}
+
+/** Machine-generated. */
+public VerifyDialog(java.awt.Dialog owner, boolean modal) {
+ super(owner, modal);
+}
+
+/** Machine-generated. */
+public VerifyDialog(java.awt.Frame owner) {
+ super(owner);
+}
+
+/** Machine-generated. */
+public VerifyDialog(java.awt.Frame owner, String title) {
+ super(owner, title);
+}
+
+/** Machine-generated. */
+public VerifyDialog(java.awt.Frame owner, String title, boolean modal) {
+ super(owner, title, modal);
+}
+
+/** Machine-generated. */
+public VerifyDialog(java.awt.Frame owner, boolean modal) {
+ super(owner, modal);
+}
+
+/**
+ * Use this constructor if you want a possibility to verify other
+ * class files than java.lang.Object.
+ * @param fully_qualified_class_name java.lang.String
+ */
+public VerifyDialog(String fully_qualified_class_name) {
+ super();
+
+ int dotclasspos = fully_qualified_class_name.lastIndexOf(".class");
+ if (dotclasspos != -1) fully_qualified_class_name = fully_qualified_class_name.substring(0,dotclasspos);
+ fully_qualified_class_name = fully_qualified_class_name.replace('/', '.');
+
+ class_name = fully_qualified_class_name;
+ initialize();
+}
+
+
+/** Machine-generated. */
+private void connEtoC1(java.awt.event.ActionEvent arg1) {
+ try {
+ // user code begin {1}
+ // user code end
+ this.pass1Button_ActionPerformed(arg1);
+ // user code begin {2}
+ // user code end
+ } catch (java.lang.Throwable ivjExc) {
+ // user code begin {3}
+ // user code end
+ handleException(ivjExc);
+ }
+}
+
+/** Machine-generated. */
+private void connEtoC2(java.awt.event.ActionEvent arg1) {
+ try {
+ // user code begin {1}
+ // user code end
+ this.pass2Button_ActionPerformed(arg1);
+ // user code begin {2}
+ // user code end
+ } catch (java.lang.Throwable ivjExc) {
+ // user code begin {3}
+ // user code end
+ handleException(ivjExc);
+ }
+}
+
+/** Machine-generated. */
+private void connEtoC3(java.awt.event.ActionEvent arg1) {
+ try {
+ // user code begin {1}
+ // user code end
+ this.pass4Button_ActionPerformed(arg1);
+ // user code begin {2}
+ // user code end
+ } catch (java.lang.Throwable ivjExc) {
+ // user code begin {3}
+ // user code end
+ handleException(ivjExc);
+ }
+}
+
+/** Machine-generated. */
+private void connEtoC4(java.awt.event.ActionEvent arg1) {
+ try {
+ // user code begin {1}
+ // user code end
+ this.flushButton_ActionPerformed(arg1);
+ // user code begin {2}
+ // user code end
+ } catch (java.lang.Throwable ivjExc) {
+ // user code begin {3}
+ // user code end
+ handleException(ivjExc);
+ }
+}
+
+/** Machine-generated. */
+public void flushButton_ActionPerformed(java.awt.event.ActionEvent actionEvent) {
+ VerifierFactory.getVerifier(class_name).flush();
+ Repository.removeClass(class_name); // Make sure it will be reloaded.
+ getPass1Panel().setBackground(Color.gray);
+ getPass1Panel().repaint();
+ getPass2Panel().setBackground(Color.gray);
+ getPass2Panel().repaint();
+ getPass3Panel().setBackground(Color.gray);
+ getPass3Panel().repaint();
+}
+
+/** Machine-generated. */
+private javax.swing.JButton getFlushButton() {
+ if (ivjFlushButton == null) {
+ try {
+ ivjFlushButton = new javax.swing.JButton();
+ ivjFlushButton.setName("FlushButton");
+ ivjFlushButton.setText("Flush: Forget old verification results");
+ ivjFlushButton.setBackground(java.awt.SystemColor.controlHighlight);
+ ivjFlushButton.setBounds(60, 215, 300, 30);
+ ivjFlushButton.setForeground(java.awt.Color.red);
+ ivjFlushButton.setActionCommand("FlushButton");
+ // user code begin {1}
+ // user code end
+ } catch (java.lang.Throwable ivjExc) {
+ // user code begin {2}
+ // user code end
+ handleException(ivjExc);
+ }
+ }
+ return ivjFlushButton;
+}
+
+/** Machine-generated. */
+private javax.swing.JPanel getJDialogContentPane() {
+ if (ivjJDialogContentPane == null) {
+ try {
+ ivjJDialogContentPane = new javax.swing.JPanel();
+ ivjJDialogContentPane.setName("JDialogContentPane");
+ ivjJDialogContentPane.setLayout(null);
+ getJDialogContentPane().add(getPass1Panel(), getPass1Panel().getName());
+ getJDialogContentPane().add(getPass3Panel(), getPass3Panel().getName());
+ getJDialogContentPane().add(getPass2Panel(), getPass2Panel().getName());
+ getJDialogContentPane().add(getPass1Button(), getPass1Button().getName());
+ getJDialogContentPane().add(getPass2Button(), getPass2Button().getName());
+ getJDialogContentPane().add(getPass3Button(), getPass3Button().getName());
+ getJDialogContentPane().add(getFlushButton(), getFlushButton().getName());
+ // user code begin {1}
+ // user code end
+ } catch (java.lang.Throwable ivjExc) {
+ // user code begin {2}
+ // user code end
+ handleException(ivjExc);
+ }
+ }
+ return ivjJDialogContentPane;
+}
+
+/** Machine-generated. */
+private javax.swing.JButton getPass1Button() {
+ if (ivjPass1Button == null) {
+ try {
+ ivjPass1Button = new javax.swing.JButton();
+ ivjPass1Button.setName("Pass1Button");
+ ivjPass1Button.setText("Pass1: Verify binary layout of .class file");
+ ivjPass1Button.setBackground(java.awt.SystemColor.controlHighlight);
+ ivjPass1Button.setBounds(100, 40, 300, 30);
+ ivjPass1Button.setActionCommand("Button1");
+ // user code begin {1}
+ // user code end
+ } catch (java.lang.Throwable ivjExc) {
+ // user code begin {2}
+ // user code end
+ handleException(ivjExc);
+ }
+ }
+ return ivjPass1Button;
+}
+
+/** Machine-generated. */
+private javax.swing.JPanel getPass1Panel() {
+ if (ivjPass1Panel == null) {
+ try {
+ ivjPass1Panel = new javax.swing.JPanel();
+ ivjPass1Panel.setName("Pass1Panel");
+ ivjPass1Panel.setLayout(null);
+ ivjPass1Panel.setBackground(java.awt.SystemColor.controlShadow);
+ ivjPass1Panel.setBounds(30, 30, 50, 50);
+ // user code begin {1}
+ // user code end
+ } catch (java.lang.Throwable ivjExc) {
+ // user code begin {2}
+ // user code end
+ handleException(ivjExc);
+ }
+ }
+ return ivjPass1Panel;
+}
+
+/** Machine-generated. */
+private javax.swing.JButton getPass2Button() {
+ if (ivjPass2Button == null) {
+ try {
+ ivjPass2Button = new javax.swing.JButton();
+ ivjPass2Button.setName("Pass2Button");
+ ivjPass2Button.setText("Pass 2: Verify static .class file constraints");
+ ivjPass2Button.setBackground(java.awt.SystemColor.controlHighlight);
+ ivjPass2Button.setBounds(100, 100, 300, 30);
+ ivjPass2Button.setActionCommand("Button2");
+ // user code begin {1}
+ // user code end
+ } catch (java.lang.Throwable ivjExc) {
+ // user code begin {2}
+ // user code end
+ handleException(ivjExc);
+ }
+ }
+ return ivjPass2Button;
+}
+
+/** Machine-generated. */
+private javax.swing.JPanel getPass2Panel() {
+ if (ivjPass2Panel == null) {
+ try {
+ ivjPass2Panel = new javax.swing.JPanel();
+ ivjPass2Panel.setName("Pass2Panel");
+ ivjPass2Panel.setLayout(null);
+ ivjPass2Panel.setBackground(java.awt.SystemColor.controlShadow);
+ ivjPass2Panel.setBounds(30, 90, 50, 50);
+ // user code begin {1}
+ // user code end
+ } catch (java.lang.Throwable ivjExc) {
+ // user code begin {2}
+ // user code end
+ handleException(ivjExc);
+ }
+ }
+ return ivjPass2Panel;
+}
+
+/** Machine-generated. */
+private javax.swing.JButton getPass3Button() {
+ if (ivjPass3Button == null) {
+ try {
+ ivjPass3Button = new javax.swing.JButton();
+ ivjPass3Button.setName("Pass3Button");
+ ivjPass3Button.setText("Passes 3a+3b: Verify code arrays");
+ ivjPass3Button.setBackground(java.awt.SystemColor.controlHighlight);
+ ivjPass3Button.setBounds(100, 160, 300, 30);
+ ivjPass3Button.setActionCommand("Button2");
+ // user code begin {1}
+ // user code end
+ } catch (java.lang.Throwable ivjExc) {
+ // user code begin {2}
+ // user code end
+ handleException(ivjExc);
+ }
+ }
+ return ivjPass3Button;
+}
+
+/** Machine-generated. */
+private javax.swing.JPanel getPass3Panel() {
+ if (ivjPass3Panel == null) {
+ try {
+ ivjPass3Panel = new javax.swing.JPanel();
+ ivjPass3Panel.setName("Pass3Panel");
+ ivjPass3Panel.setLayout(null);
+ ivjPass3Panel.setBackground(java.awt.SystemColor.controlShadow);
+ ivjPass3Panel.setBounds(30, 150, 50, 50);
+ // user code begin {1}
+ // user code end
+ } catch (java.lang.Throwable ivjExc) {
+ // user code begin {2}
+ // user code end
+ handleException(ivjExc);
+ }
+ }
+ return ivjPass3Panel;
+}
+
+/** Machine-generated. */
+private void handleException(java.lang.Throwable exception) {
+
+ /* Uncomment the following lines to print uncaught exceptions to stdout */
+ System.out.println("--------- UNCAUGHT EXCEPTION ---------");
+ exception.printStackTrace(System.out);
+}
+
+
+/** Machine-generated. */
+private void initConnections() throws java.lang.Exception {
+ // user code begin {1}
+ // user code end
+ getPass1Button().addActionListener(ivjEventHandler);
+ getPass2Button().addActionListener(ivjEventHandler);
+ getPass3Button().addActionListener(ivjEventHandler);
+ getFlushButton().addActionListener(ivjEventHandler);
+}
+
+/** Machine-generated. */
+private void initialize() {
+ try {
+ // user code begin {1}
+ // user code end
+ setName("VerifyDialog");
+ setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+ setSize(430, 280);
+ setVisible(true);
+ setModal(true);
+ setResizable(false);
+ setContentPane(getJDialogContentPane());
+ initConnections();
+ } catch (java.lang.Throwable ivjExc) {
+ handleException(ivjExc);
+ }
+ // user code begin {2}
+ setTitle("'"+class_name+"' verification - JustIce / BCEL");
+ // user code end
+}
+/**
+ * Verifies one or more class files.
+ * Verification results are presented graphically: Red means 'rejected',
+ * green means 'passed' while yellow means 'could not be verified yet'.
+ * @param args java.lang.String[] fully qualified names of classes to verify.
+ */
+public static void main(java.lang.String[] args) {
+ classes_to_verify = args.length;
+
+ for (int i=0; i<args.length; i++){
+
+ try {
+ VerifyDialog aVerifyDialog;
+ aVerifyDialog = new VerifyDialog(args[i]);
+ aVerifyDialog.setModal(true);
+ aVerifyDialog.addWindowListener(new java.awt.event.WindowAdapter() {
+ public void windowClosing(java.awt.event.WindowEvent e) {
+ classes_to_verify--;
+ if (classes_to_verify == 0) System.exit(0);
+ };
+ });
+ aVerifyDialog.setVisible(true);
+ } catch (Throwable exception) {
+ System.err.println("Exception occurred in main() of javax.swing.JDialog");
+ exception.printStackTrace(System.out);
+ }
+
+ }
+}
+
+/** Machine-generated. */
+public void pass1Button_ActionPerformed(java.awt.event.ActionEvent actionEvent) {
+ Verifier v = VerifierFactory.getVerifier(class_name);
+ VerificationResult vr = v.doPass1();
+ if (vr.getStatus() == VerificationResult.VERIFIED_OK){
+ getPass1Panel().setBackground(Color.green);
+ getPass1Panel().repaint();
+ }
+ if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED){
+ getPass1Panel().setBackground(Color.red);
+ getPass1Panel().repaint();
+ }
+}
+
+/** Machine-generated. */
+public void pass2Button_ActionPerformed(java.awt.event.ActionEvent actionEvent) {
+ pass1Button_ActionPerformed(actionEvent);
+
+ Verifier v = VerifierFactory.getVerifier(class_name);
+ VerificationResult vr = v.doPass2();
+ if (vr.getStatus() == VerificationResult.VERIFIED_OK){
+ getPass2Panel().setBackground(Color.green);
+ getPass2Panel().repaint();
+ }
+ if (vr.getStatus() == VerificationResult.VERIFIED_NOTYET){
+ getPass2Panel().setBackground(Color.yellow);
+ getPass2Panel().repaint();
+ }
+ if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED){
+ getPass2Panel().setBackground(Color.red);
+ getPass2Panel().repaint();
+ }
+}
+
+/** Machine-generated. */
+public void pass4Button_ActionPerformed(java.awt.event.ActionEvent actionEvent) {
+
+ pass2Button_ActionPerformed(actionEvent);
+
+
+ Color color = Color.green;
+
+ Verifier v = VerifierFactory.getVerifier(class_name);
+ VerificationResult vr = v.doPass2();
+ if (vr.getStatus() == VerificationResult.VERIFIED_OK){
+ JavaClass jc = Repository.lookupClass(class_name);
+ int nr = jc.getMethods().length;
+ for (int i=0; i<nr; i++) {
+ vr = v.doPass3b(i);
+ if (vr.getStatus() != VerificationResult.VERIFIED_OK){
+ color = Color.red;
+ break;
+ }
+ }
+ }
+ else{
+ color = Color.yellow;
+ }
+
+ getPass3Panel().setBackground(color);
+ getPass3Panel().repaint();
+}
+}
diff --git a/src/java/org/apache/bcel/verifier/exc/AssertionViolatedException.java b/src/java/org/apache/bcel/verifier/exc/AssertionViolatedException.java
new file mode 100644
index 00000000..91b8c6b7
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/exc/AssertionViolatedException.java
@@ -0,0 +1,115 @@
+package org.apache.bcel.verifier.exc;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/**
+ * Instances of this class should never be thrown. When such an instance is thrown,
+ * this is due to an INTERNAL ERROR of BCEL's class file verifier &quot;JustIce&quot;.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public final class AssertionViolatedException extends RuntimeException{
+ /** The error message. */
+ private String detailMessage;
+ /** Constructs a new AssertionViolatedException with null as its error message string. */
+ public AssertionViolatedException(){
+ super();
+ }
+ /**
+ * Constructs a new AssertionViolatedException with the specified error message preceded
+ * by &quot;INTERNAL ERROR: &quot;.
+ */
+ public AssertionViolatedException(String message){
+ super(message = "INTERNAL ERROR: "+message); // Thanks to Java, the constructor call here must be first.
+ detailMessage=message;
+ }
+ /** Extends the error message with a string before ("pre") and after ("post") the
+ 'old' error message. All of these three strings are allowed to be null, and null
+ is always replaced by the empty string (""). In particular, after invoking this
+ method, the error message of this object can no longer be null.
+ */
+ public void extendMessage(String pre, String post){
+ if (pre == null) pre="";
+ if (detailMessage == null) detailMessage="";
+ if (post == null) post="";
+ detailMessage = pre+detailMessage+post;
+ }
+ /**
+ * Returns the error message string of this AssertionViolatedException object.
+ * @return the error message string of this AssertionViolatedException.
+ */
+ public String getMessage(){
+ return detailMessage;
+ }
+
+ /**
+ * DO NOT USE. It's for experimental testing during development only.
+ */
+ public static void main(String[] args){
+ AssertionViolatedException ave = new AssertionViolatedException("Oops!");
+ ave.extendMessage("\nFOUND:\n\t","\nExiting!!\n");
+ throw ave;
+ }
+
+ /**
+ * Returns the backtrace of this AssertionViolatedException as a String.
+ * @return The backtrace of this AssertionViolatedException as a String.
+ */
+ public String getStackTrace(){
+ return Utility.getStackTrace(this);
+ }
+
+}
diff --git a/src/java/org/apache/bcel/verifier/exc/ClassConstraintException.java b/src/java/org/apache/bcel/verifier/exc/ClassConstraintException.java
new file mode 100644
index 00000000..11b67f24
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/exc/ClassConstraintException.java
@@ -0,0 +1,83 @@
+package org.apache.bcel.verifier.exc;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/**
+ * Instances of this class are thrown by BCEL's class file verifier "JustIce"
+ * when a class file to verify does not pass the verification pass 2 as described
+ * in the Java Virtual Machine specification, 2nd edition.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class ClassConstraintException extends VerificationException{
+ /** The specified error message. */
+ private String detailMessage;
+
+ /**
+ * Constructs a new ClassConstraintException with null as its error message string.
+ */
+ public ClassConstraintException(){
+ super();
+ }
+
+ /**
+ * Constructs a new ClassConstraintException with the specified error message.
+ */
+ public ClassConstraintException(String message){
+ super (message);
+ detailMessage = message;
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/exc/CodeConstraintException.java b/src/java/org/apache/bcel/verifier/exc/CodeConstraintException.java
new file mode 100644
index 00000000..14dfd4f7
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/exc/CodeConstraintException.java
@@ -0,0 +1,77 @@
+package org.apache.bcel.verifier.exc;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+/**
+ * Instances of this class are thrown by BCEL's class file verifier "JustIce" when
+ * a class file does not pass the verification pass 3. Note that the pass 3 used by
+ * "JustIce" involves verification that is usually delayed to pass 4.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public abstract class CodeConstraintException extends VerificationException{
+ /**
+ * Constructs a new CodeConstraintException with null as its error message string.
+ */
+ CodeConstraintException(){
+ super();
+ }
+ /**
+ * Constructs a new CodeConstraintException with the specified error message.
+ */
+ CodeConstraintException(String message){
+ super(message);
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/exc/InvalidMethodException.java b/src/java/org/apache/bcel/verifier/exc/InvalidMethodException.java
new file mode 100644
index 00000000..5101b632
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/exc/InvalidMethodException.java
@@ -0,0 +1,71 @@
+package org.apache.bcel.verifier.exc;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+/**
+ * Instances of this class are thrown by BCEL's class file verifier "JustIce"
+ * when the verification of a method is requested that does not exist.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class InvalidMethodException extends RuntimeException{
+ /** Must not be no-args requested so there's always some error message. */
+ private InvalidMethodException(){}
+
+ /** Constructs an InvalidMethodException with the specified detail message. */
+ public InvalidMethodException(String message){
+ super(message);
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/exc/LinkingConstraintException.java b/src/java/org/apache/bcel/verifier/exc/LinkingConstraintException.java
new file mode 100644
index 00000000..6ca913c4
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/exc/LinkingConstraintException.java
@@ -0,0 +1,74 @@
+package org.apache.bcel.verifier.exc;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+/**
+ * Instances of this class are thrown by BCEL's class file verifier "JustIce" when
+ * a class file to verify does not pass the verification pass 3 because of a violation
+ * of a constraint that is usually only verified at run-time (pass 4).
+ * The Java Virtual Machine Specification, 2nd edition, states that certain constraints
+ * are usually verified at run-time for performance reasons (the verification of those
+ * constraints requires loading in and recursively verifying referenced classes) that
+ * conceptually belong to pass 3; to be precise, that conceptually belong to the
+ * data flow analysis of pass 3 (called pass 3b in JustIce).
+ * These are the checks necessary for resolution: Compare pages 142-143 ("4.9.1 The
+ * Verification Process") and pages 50-51 ("2.17.3 Linking: Verification, Preparation,
+ * and Resolution") of the above mentioned book.
+ * <B>TODO: At this time, this class is not used in JustIce.</B>
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class LinkingConstraintException extends StructuralCodeConstraintException{
+}
diff --git a/src/java/org/apache/bcel/verifier/exc/LoadingException.java b/src/java/org/apache/bcel/verifier/exc/LoadingException.java
new file mode 100644
index 00000000..4e17e6cd
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/exc/LoadingException.java
@@ -0,0 +1,82 @@
+package org.apache.bcel.verifier.exc;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/**
+ * When loading a class file, BCEL will throw an instance of LoadingException if
+ * the class file is malformed; so it is not conforming to the "Pass 1" verification
+ * process as described in the Java Virtual Machine specification, 2nd. edition.
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class LoadingException extends VerifierConstraintViolatedException{
+ /** The specified error message. */
+ private String detailMessage;
+
+ /**
+ * Constructs a new LoadingException with null as its error message string.
+ */
+ public LoadingException(){
+ super();
+ }
+
+ /**
+ * Constructs a new LoadingException with the specified error message.
+ */
+ public LoadingException(String message){
+ super (message);
+ detailMessage = message;
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/exc/LocalVariableInfoInconsistentException.java b/src/java/org/apache/bcel/verifier/exc/LocalVariableInfoInconsistentException.java
new file mode 100644
index 00000000..2a52743d
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/exc/LocalVariableInfoInconsistentException.java
@@ -0,0 +1,81 @@
+package org.apache.bcel.verifier.exc;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/**
+ * A LocalVariableInfoInconsistentException instance is thrown by
+ * the LocalVariableInfo class when it detects that the information
+ * it holds is inconsistent; this is normally due to inconsistent
+ * LocalVariableTable entries in the Code attribute of a certain
+ * Method object.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class LocalVariableInfoInconsistentException extends ClassConstraintException{
+ /**
+ * Constructs a new LocalVariableInfoInconsistentException with null as its error message string.
+ */
+ public LocalVariableInfoInconsistentException(){
+ super();
+ }
+
+ /**
+ * Constructs a new LocalVariableInfoInconsistentException with the specified error message.
+ */
+ public LocalVariableInfoInconsistentException(String message){
+ super (message);
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/exc/StaticCodeConstraintException.java b/src/java/org/apache/bcel/verifier/exc/StaticCodeConstraintException.java
new file mode 100644
index 00000000..86b0fd3b
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/exc/StaticCodeConstraintException.java
@@ -0,0 +1,71 @@
+package org.apache.bcel.verifier.exc;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/**
+ * Instances of this class are thrown by BCEL's class file verifier "JustIce" when
+ * a class file to verify does not pass the verification pass 3 because of a violation
+ * of a static constraint as described in the Java Virtual Machine Specification,
+ * 2nd edition, 4.8.1, pages 133-137. The static constraints checking part of pass 3
+ * is called pass 3a in JustIce.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public abstract class StaticCodeConstraintException extends CodeConstraintException{
+ public StaticCodeConstraintException(String message){
+ super(message);
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/exc/StaticCodeInstructionConstraintException.java b/src/java/org/apache/bcel/verifier/exc/StaticCodeInstructionConstraintException.java
new file mode 100644
index 00000000..43a8a3f7
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/exc/StaticCodeInstructionConstraintException.java
@@ -0,0 +1,74 @@
+package org.apache.bcel.verifier.exc;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/**
+ * Instances of this class are thrown by BCEL's class file verifier "JustIce" when
+ * a class file to verify does not pass the verification pass 3 because of a violation
+ * of a static constraint as described in the Java Virtual Machine Specification,
+ * Second edition, 4.8.1, pages 133-137. The static constraints checking part of pass 3
+ * is called pass 3a in JustIce.
+ * Static constraints on the instructions in the code array are checked early in
+ * pass 3a and are described on page 134 in the Java Virtual Machine Specification,
+ * Second Edition.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class StaticCodeInstructionConstraintException extends StaticCodeConstraintException{
+ public StaticCodeInstructionConstraintException(String message){
+ super(message);
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/exc/StaticCodeInstructionOperandConstraintException.java b/src/java/org/apache/bcel/verifier/exc/StaticCodeInstructionOperandConstraintException.java
new file mode 100644
index 00000000..3825a741
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/exc/StaticCodeInstructionOperandConstraintException.java
@@ -0,0 +1,74 @@
+package org.apache.bcel.verifier.exc;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/**
+ * Instances of this class are thrown by BCEL's class file verifier "JustIce" when
+ * a class file to verify does not pass the verification pass 3 because of a violation
+ * of a static constraint as described in the Java Virtual Machine Specification,
+ * Second edition, 4.8.1, pages 133-137. The static constraints checking part of pass 3
+ * is called pass 3a in JustIce.
+ * Static constraints on the operands of instructions in the code array are checked late in
+ * pass 3a and are described on page 134-137 in the Java Virtual Machine Specification,
+ * Second Edition.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class StaticCodeInstructionOperandConstraintException extends StaticCodeConstraintException{
+ public StaticCodeInstructionOperandConstraintException(String message){
+ super(message);
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/exc/StructuralCodeConstraintException.java b/src/java/org/apache/bcel/verifier/exc/StructuralCodeConstraintException.java
new file mode 100644
index 00000000..946f1044
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/exc/StructuralCodeConstraintException.java
@@ -0,0 +1,82 @@
+package org.apache.bcel.verifier.exc;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+/**
+ * Instances of this class are thrown by BCEL's class file verifier "JustIce" when
+ * a class file to verify does not pass the verification pass 3 because of a violation
+ * of a structural constraint as described in the Java Virtual Machine Specification,
+ * 2nd edition, 4.8.2, pages 137-139.
+ * Note that the notion of a "structural" constraint is somewhat misleading. Structural
+ * constraints are constraints on relationships between Java virtual machine instructions.
+ * These are the constraints where data-flow analysis is needed to verify if they hold.
+ * The data flow analysis of pass 3 is called pass 3b in JustIce.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class StructuralCodeConstraintException extends CodeConstraintException{
+ /**
+ * Constructs a new StructuralCodeConstraintException with the specified error message.
+ */
+ public StructuralCodeConstraintException(String message){
+ super(message);
+ }
+ /**
+ * Constructs a new StructuralCodeConstraintException with null as its error message string.
+ */
+ public StructuralCodeConstraintException(){
+ super();
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/exc/Utility.java b/src/java/org/apache/bcel/verifier/exc/Utility.java
new file mode 100644
index 00000000..01b80cea
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/exc/Utility.java
@@ -0,0 +1,76 @@
+package org.apache.bcel.verifier.exc;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import java.io.*;
+
+/**
+ * A utility class providing convenience methods concerning Throwable instances.
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ * @see java.lang.Throwable
+ */
+public final class Utility{
+ /** This class is not instantiable. */
+ private Utility(){}
+
+ /** This method returns the stack trace of a Throwable instance as a String. */
+ public static String getStackTrace(Throwable t){
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ t.printStackTrace(pw);
+ return sw.toString();
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/exc/VerificationException.java b/src/java/org/apache/bcel/verifier/exc/VerificationException.java
new file mode 100644
index 00000000..d8d473fa
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/exc/VerificationException.java
@@ -0,0 +1,82 @@
+package org.apache.bcel.verifier.exc;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/**
+ * Instances of this class are thrown by BCEL's class file verifier "JustIce" when a
+ * class file to verify does not pass one of the verification passes 2 or 3.
+ * Note that the pass 3 used by "JustIce" involves verification that is usually
+ * delayed to pass 4.
+ * The name of this class is justified by the Java Virtual Machine Specification, 2nd
+ * edition, page 164, 5.4.1 where verification as a part of the linking process is
+ * defined to be the verification happening in passes 2 and 3.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public abstract class VerificationException extends VerifierConstraintViolatedException{
+ /**
+ * Constructs a new VerificationException with null as its error message string.
+ */
+ VerificationException(){
+ super();
+ }
+ /**
+ * Constructs a new VerificationException with the specified error message.
+ */
+ VerificationException(String message){
+ super(message);
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/exc/VerifierConstraintViolatedException.java b/src/java/org/apache/bcel/verifier/exc/VerifierConstraintViolatedException.java
new file mode 100644
index 00000000..65dd1e96
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/exc/VerifierConstraintViolatedException.java
@@ -0,0 +1,107 @@
+package org.apache.bcel.verifier.exc;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/**
+ * Instances of this class are thrown by BCEL's class file verifier "JustIce"
+ * whenever
+ * verification proves that some constraint of a class file (as stated in the
+ * Java Virtual Machine Specification, Edition 2) is violated.
+ * This is roughly equivalent to the VerifyError the JVM-internal verifiers
+ * throw.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public abstract class VerifierConstraintViolatedException extends RuntimeException{
+ // /** The name of the offending class that did not pass the verifier. */
+ // String name_of_offending_class;
+
+ /** The specified error message. */
+ private String detailMessage;
+ /**
+ * Constructs a new VerifierConstraintViolatedException with null as its error message string.
+ */
+ VerifierConstraintViolatedException(){
+ super();
+ }
+ /**
+ * Constructs a new VerifierConstraintViolatedException with the specified error message.
+ */
+ VerifierConstraintViolatedException(String message){
+ super(message); // Not that important
+ detailMessage = message;
+ }
+
+
+ /** Extends the error message with a string before ("pre") and after ("post") the
+ 'old' error message. All of these three strings are allowed to be null, and null
+ is always replaced by the empty string (""). In particular, after invoking this
+ method, the error message of this object can no longer be null.
+ */
+ public void extendMessage(String pre, String post){
+ if (pre == null) pre="";
+ if (detailMessage == null) detailMessage="";
+ if (post == null) post="";
+ detailMessage = pre+detailMessage+post;
+ }
+ /**
+ * Returns the error message string of this VerifierConstraintViolatedException object.
+ * @return the error message string of this VerifierConstraintViolatedException.
+ */
+ public String getMessage(){
+ return detailMessage;
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/exc/package.html b/src/java/org/apache/bcel/verifier/exc/package.html
new file mode 100644
index 00000000..3d04b1b5
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/exc/package.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+$Id$
+-->
+</head>
+<body bgcolor="white">
+
+Exception classes used by JustIce, mostly used internally. You don't need to bother with them.
+
+<h2>Package Specification</h2>
+
+Contained in this package are Exception classes for use with the JustIce verifier.
+
+<h2>Related Documentation</h2>
+
+For a simple demonstration of JustIce working, please see:
+<ul>
+ <li><a href="http://www.inf.fu-berlin.de/~ehaase/cgi-html/Verifier.html">A WWW front-end for JustIce.</a>
+</ul>
+
+</body>
+</html>
diff --git a/src/java/org/apache/bcel/verifier/package.html b/src/java/org/apache/bcel/verifier/package.html
new file mode 100644
index 00000000..5f73d77d
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/package.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+$Id$
+-->
+</head>
+<body bgcolor="white">
+
+BCEL's verifier JustIce is there to help you dump correct Java class files created or modified with BCEL.
+
+<h2>Package Specification</h2>
+
+This is the top-level package of the JustIce verifier. To actually use it, have a look at the VerifierFactory and
+Verifier classes.
+
+<h2>Related Documentation</h2>
+
+For a simple demonstration of JustIce working, please see:
+<ul>
+ <li><a href="http://www.inf.fu-berlin.de/~ehaase/cgi-html/Verifier.html">A WWW front-end for JustIce.</a>
+</ul>
+
+</body>
+</html>
diff --git a/src/java/org/apache/bcel/verifier/statics/DOUBLE_Upper.java b/src/java/org/apache/bcel/verifier/statics/DOUBLE_Upper.java
new file mode 100644
index 00000000..108988c4
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/statics/DOUBLE_Upper.java
@@ -0,0 +1,79 @@
+package org.apache.bcel.verifier.statics;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.Constants;
+import org.apache.bcel.generic.Type;
+
+/**
+ * This class represents the upper half of a DOUBLE variable.
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public final class DOUBLE_Upper extends Type{
+
+ /** The one and only instance of this class. */
+ private static DOUBLE_Upper singleInstance = new DOUBLE_Upper();
+
+ /** The constructor; this class must not be instantiated from the outside. */
+ private DOUBLE_Upper(){
+ super(Constants.T_UNKNOWN, "Long_Upper");
+ }
+
+ /** Use this method to get the single instance of this class. */
+ public static DOUBLE_Upper theInstance(){
+ return singleInstance;
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/statics/IntList.java b/src/java/org/apache/bcel/verifier/statics/IntList.java
new file mode 100644
index 00000000..bc45fda1
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/statics/IntList.java
@@ -0,0 +1,85 @@
+package org.apache.bcel.verifier.statics;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import java.util.ArrayList;
+
+/**
+ * A small utility class representing a set of basic int values.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class IntList{
+ /** The int are stored as Integer objects here. */
+ private ArrayList theList;
+ /** This constructor creates an empty list. */
+ IntList(){
+ theList = new ArrayList();
+ }
+ /** Adds an element to the list. */
+ void add(int i){
+ theList.add(new Integer(i));
+ }
+ /** Checks if the specified int is already in the list. */
+ boolean contains(int i){
+ Integer[] ints = new Integer[theList.size()];
+ theList.toArray(ints);
+ for (int j=0; j<ints.length; j++){
+ if (i == ints[j].intValue()) return true;
+ }
+ return false;
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/statics/LONG_Upper.java b/src/java/org/apache/bcel/verifier/statics/LONG_Upper.java
new file mode 100644
index 00000000..b1d1defe
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/statics/LONG_Upper.java
@@ -0,0 +1,79 @@
+package org.apache.bcel.verifier.statics;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.Constants;
+import org.apache.bcel.generic.Type;
+
+/**
+ * This class represents the upper half of a LONG variable.
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public final class LONG_Upper extends Type{
+
+ /** The one and only instance of this class. */
+ private static LONG_Upper singleInstance = new LONG_Upper();
+
+ /** The constructor; this class must not be instantiated from the outside. */
+ private LONG_Upper(){
+ super(Constants.T_UNKNOWN, "Long_Upper");
+ }
+
+ /** Use this method to get the single instance of this class. */
+ public static LONG_Upper theInstance(){
+ return singleInstance;
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/statics/LocalVariableInfo.java b/src/java/org/apache/bcel/verifier/statics/LocalVariableInfo.java
new file mode 100644
index 00000000..2c9a7dec
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/statics/LocalVariableInfo.java
@@ -0,0 +1,145 @@
+package org.apache.bcel.verifier.statics;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.Constants;
+import org.apache.bcel.generic.Type;
+import org.apache.bcel.verifier.exc.*;
+import java.util.Hashtable;
+
+/**
+ * A utility class holding the information about
+ * the name and the type of a local variable in
+ * a given slot (== index). This information
+ * often changes in course of byte code offsets.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class LocalVariableInfo{
+
+ /** The types database. KEY: String representing the offset integer. */
+ private Hashtable types = new Hashtable();
+ /** The names database. KEY: String representing the offset integer. */
+ private Hashtable names = new Hashtable();
+
+ /**
+ * Adds a name of a local variable and a certain slot to our 'names'
+ * (Hashtable) database.
+ */
+ private void setName(int offset, String name){
+ names.put( ((Integer.toString(offset))), name);
+ }
+ /**
+ * Adds a type of a local variable and a certain slot to our 'types'
+ * (Hashtable) database.
+ */
+ private void setType(int offset, Type t){
+ types.put( ((Integer.toString(offset))), t);
+ }
+
+ /**
+ * Returns the type of the local variable that uses this local
+ * variable slot at the given bytecode offset.
+ * Care for legal bytecode offsets yourself, otherwise the return value
+ * might be wrong.
+ * May return 'null' if nothing is known about the type of this local
+ * variable slot at the given bytecode offset.
+ */
+ public Type getType(int offset){
+ return (Type) types.get(Integer.toString(offset));
+ }
+ /**
+ * Returns the name of the local variable that uses this local
+ * variable slot at the given bytecode offset.
+ * Care for legal bytecode offsets yourself, otherwise the return value
+ * might be wrong.
+ * May return 'null' if nothing is known about the type of this local
+ * variable slot at the given bytecode offset.
+ */
+ public String getName(int offset){
+ return (String) (names.get(Integer.toString(offset)));
+ }
+ /**
+ * Adds some information about this local variable (slot).
+ * @throws LocalVariableInfoInconsistentException if the new information conflicts
+ * with already gathered information.
+ */
+ public void add(String name, int startpc, int length, Type t) throws LocalVariableInfoInconsistentException{
+ for (int i=startpc; i<=startpc+length; i++){ // incl/incl-notation!
+ add(i,name,t);
+ }
+ }
+
+ /**
+ * Adds information about name and type for a given offset.
+ * @throws LocalVariableInfoInconsistentException if the new information conflicts
+ * with already gathered information.
+ */
+ private void add(int offset, String name, Type t) throws LocalVariableInfoInconsistentException{
+ if (getName(offset) != null){
+ if (! getName(offset).equals(name)){
+ throw new LocalVariableInfoInconsistentException("At bytecode offset '"+offset+"' a local variable has two different names: '"+getName(offset)+"' and '"+name+"'.");
+ }
+ }
+ if (getType(offset) != null){
+ if (! getType(offset).equals(t)){
+ throw new LocalVariableInfoInconsistentException("At bytecode offset '"+offset+"' a local variable has two different types: '"+getType(offset)+"' and '"+t+"'.");
+ }
+ }
+ setName(offset, name);
+ setType(offset, t);
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/statics/LocalVariablesInfo.java b/src/java/org/apache/bcel/verifier/statics/LocalVariablesInfo.java
new file mode 100644
index 00000000..221e6ab9
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/statics/LocalVariablesInfo.java
@@ -0,0 +1,113 @@
+package org.apache.bcel.verifier.statics;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.Constants;
+import org.apache.bcel.generic.Type;
+import org.apache.bcel.verifier.exc.*;
+
+/**
+ * A utility class holding the information about
+ * the names and the types of the local variables in
+ * a given method.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class LocalVariablesInfo{
+
+ /** The information about the local variables is stored here. */
+ private LocalVariableInfo[] localVariableInfos;
+
+ /**
+ * The ints in the list represent code offsets where either instructions must start
+ * or the offset is the length of the code array. This will be verified in Pass 3a.
+ */
+ private IntList instruction_offsets = new IntList();
+
+ /** The constructor. */
+ LocalVariablesInfo(int max_locals){
+ localVariableInfos = new LocalVariableInfo[max_locals];
+ for (int i=0; i<max_locals; i++){
+ localVariableInfos[i] = new LocalVariableInfo();
+ }
+ }
+
+ /** Returns the LocalVariableInfo for the given slot. */
+ public LocalVariableInfo getLocalVariableInfo(int slot){
+ if (slot < 0 || slot >= localVariableInfos.length){
+ throw new AssertionViolatedException("Slot number for local variable information out of range.");
+ }
+ return localVariableInfos[slot];
+ }
+
+ /**
+ * Adds information about the local variable in slot 'slot'. Automatically
+ * adds information for slot+1 if 't' is Type.LONG or Type.DOUBLE.
+ * @throws LocalVariableInfoInconsistentException if the new information conflicts
+ * with already gathered information.
+ */
+ public void add(int slot, String name, int startpc, int length, Type t) throws LocalVariableInfoInconsistentException{
+ // The add operation on LocalVariableInfo may throw the '...Inconsistent...' exception, we don't throw it explicitely here.
+
+ if (slot < 0 || slot >= localVariableInfos.length){
+ throw new AssertionViolatedException("Slot number for local variable information out of range.");
+ }
+
+ localVariableInfos[slot].add(name, startpc, length, t);
+ if (t == Type.LONG) localVariableInfos[slot+1].add(name, startpc, length, LONG_Upper.theInstance());
+ if (t == Type.DOUBLE) localVariableInfos[slot+1].add(name, startpc, length, DOUBLE_Upper.theInstance());
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/statics/Pass1Verifier.java b/src/java/org/apache/bcel/verifier/statics/Pass1Verifier.java
new file mode 100644
index 00000000..4b1e8c00
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/statics/Pass1Verifier.java
@@ -0,0 +1,214 @@
+package org.apache.bcel.verifier.statics;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.classfile.*;
+import org.apache.bcel.Repository;
+import org.apache.bcel.verifier.*;
+import org.apache.bcel.verifier.exc.*;
+import org.apache.bcel.verifier.exc.Utility;
+import java.util.ArrayList;
+
+/**
+ * This PassVerifier verifies a class file according to pass 1 as
+ * described in The Java Virtual Machine Specification, 2nd edition.
+ * More detailed information is to be found at the do_verify() method's
+ * documentation.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ * @see #do_verify()
+ */
+public final class Pass1Verifier extends PassVerifier{
+ /**
+ * DON'T USE THIS EVEN PRIVATELY! USE getJavaClass() INSTEAD.
+ * @see #getJavaClass()
+ */
+ private JavaClass jc;
+
+ /**
+ * The Verifier that created this.
+ */
+ private Verifier myOwner;
+
+ /** Used to load in and return the myOwner-matching JavaClass object when needed. Avoids loading in a class file when it's not really needed! */
+ private JavaClass getJavaClass(){
+ if (jc == null){
+ jc = Repository.lookupClass(myOwner.getClassName());
+ }
+ return jc;
+ }
+
+ /**
+ * Should only be instantiated by a Verifier.
+ *
+ * @see org.apache.bcel.verifier.Verifier
+ */
+ public Pass1Verifier(Verifier owner){
+ myOwner = owner;
+ }
+
+ /**
+ * Pass-one verification basically means loading in a class file.
+ * The Java Virtual Machine Specification is not too precise about
+ * what makes the difference between passes one and two.
+ * The answer is that only pass one is performed on a class file as
+ * long as its resolution is not requested; whereas pass two and
+ * pass three are performed during the resolution process.
+ * Only four constraints to be checked are explicitely stated by
+ * The Java Virtual Machine Specification, 2nd edition:
+ * <UL>
+ * <LI>The first four bytes must contain the right magic number (0xCAFEBABE).
+ * <LI>All recognized attributes must be of the proper length.
+ * <LI>The class file must not be truncated or have extra bytes at the end.
+ * <LI>The constant pool must not contain any superficially unrecognizable information.
+ * </UL>
+ * A more in-depth documentation of what pass one should do was written by
+ * <A HREF=mailto:pwfong@cs.sfu.ca>Philip W. L. Fong</A>:
+ * <UL>
+ * <LI> the file should not be truncated.
+ * <LI> the file should not have extra bytes at the end.
+ * <LI> all variable-length structures should be well-formatted:
+ * <UL>
+ * <LI> there should only be constant_pool_count-1 many entries in the constant pool.
+ * <LI> all constant pool entries should have size the same as indicated by their type tag.
+ * <LI> there are exactly interfaces_count many entries in the interfaces array of the class file.
+ * <LI> there are exactly fields_count many entries in the fields array of the class file.
+ * <LI> there are exactly methods_count many entries in the methods array of the class file.
+ * <LI> there are exactly attributes_count many entries in the attributes array of the class file, fields, methods, and code attribute.
+ * <LI> there should be exactly attribute_length many bytes in each attribute. Inconsistency between attribute_length and the actually size of the attribute content should be uncovered. For example, in an Exceptions attribute, the actual number of exceptions as required by the number_of_exceptions field might yeild an attribute size that doesn't match the attribute_length. Such an anomaly should be detected.
+ * <LI> all attributes should have proper length. In particular, under certain context (e.g. while parsing method_info), recognizable attributes (e.g. "Code" attribute) should have correct format (e.g. attribute_length is 2).
+ * </UL>
+ * <LI> Also, certain constant values are checked for validity:
+ * <UL>
+ * <LI> The magic number should be 0xCAFEBABE.
+ * <LI> The major and minor version numbers are valid.
+ * <LI> All the constant pool type tags are recognizable.
+ * <LI> All undocumented access flags are masked off before use. Strictly speaking, this is not really a check.
+ * <LI> The field this_class should point to a string that represents a legal non-array class name, and this name should be the same as the class file being loaded.
+ * <LI> the field super_class should point to a string that represents a legal non-array class name.
+ * <LI> Because some of the above checks require cross referencing the constant pool entries, guards are set up to make sure that the referenced entries are of the right type and the indices are within the legal range (0 < index < constant_pool_count).
+ * </UL>
+ * <LI> Extra checks done in pass 1:
+ * <UL>
+ * <LI> the constant values of static fields should have the same type as the fields.
+ * <LI> the number of words in a parameter list does not exceed 255 and locals_max.
+ * <LI> the name and signature of fields and methods are verified to be of legal format.
+ * </UL>
+ * </UL>
+ * (From the Paper <A HREF=http://www.cs.sfu.ca/people/GradStudents/pwfong/personal/JVM/pass1/>The Mysterious Pass One, first draft, September 2, 1997</A>.)
+ * </BR>
+ * However, most of this is done by parsing a class file or generating a class file into BCEL's internal data structure.
+ * <B>Therefore, all that is really done here is look up the class file from BCEL's repository.</B>
+ * This is also motivated by the fact that some omitted things
+ * (like the check for extra bytes at the end of the class file) are handy when actually using BCEL to repair a class file (otherwise you would not be
+ * able to load it into BCEL).
+ *
+ * @see org.apache.bcel.Repository
+ */
+ public VerificationResult do_verify(){
+ JavaClass jc;
+ try{
+ jc = getJavaClass(); //loads in the class file if not already done.
+
+ if (jc != null){
+ /* If we find more constraints to check, we should do this in an own method. */
+ if (! myOwner.getClassName().equals(jc.getClassName())){
+ // This should maybe caught by BCEL: In case of renamed .class files we get wrong
+ // JavaClass objects here.
+ throw new LoadingException("Wrong name: the internal name of the .class file '"+jc.getClassName()+"' does not match the file's name '"+myOwner.getClassName()+"'.");
+ }
+ }
+
+ }
+ catch(LoadingException e){
+ return new VerificationResult(VerificationResult.VERIFIED_REJECTED, e.getMessage());
+ }
+ catch(ClassFormatError e){
+ // BCEL sometimes is a little harsh describing exceptual situations.
+ return new VerificationResult(VerificationResult.VERIFIED_REJECTED, e.getMessage());
+ }
+ catch(RuntimeException e){
+ // BCEL does not catch every possible RuntimeException; e.g. if
+ // a constant pool index is referenced that does not exist.
+ return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Parsing via BCEL did not succeed. "+e.getClass().getName()+" occured:\n"+Utility.getStackTrace(e));
+ }
+
+ if (jc != null){
+ return VerificationResult.VR_OK;
+ }
+ else{
+ //TODO: Maybe change Repository's behaviour to throw a LoadingException instead of just returning "null"
+ // if a class file cannot be found or in another way be looked up.
+ return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Repository.lookup() failed. FILE NOT FOUND?");
+ }
+ }
+
+ /**
+ * Currently this returns an empty array of String.
+ * One could parse the error messages of BCEL
+ * (written to java.lang.System.err) when loading
+ * a class file such as detecting unknown attributes
+ * or trailing garbage at the end of a class file.
+ * However, Markus Dahm does not like the idea so this
+ * method is currently useless and therefore marked as
+ * <B>TODO</B>.
+ */
+ public String[] getMessages(){
+ // This method is only here to override the javadoc-comment.
+ return super.getMessages();
+ }
+
+}
diff --git a/src/java/org/apache/bcel/verifier/statics/Pass2Verifier.java b/src/java/org/apache/bcel/verifier/statics/Pass2Verifier.java
new file mode 100644
index 00000000..7c41d1fb
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/statics/Pass2Verifier.java
@@ -0,0 +1,1334 @@
+package org.apache.bcel.verifier.statics;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.Constants;
+import org.apache.bcel.Repository;
+import org.apache.bcel.classfile.*;
+import org.apache.bcel.classfile.DescendingVisitor; // Use _this_ one!
+import org.apache.bcel.classfile.EmptyVisitor; // Use _this_ one!
+import org.apache.bcel.classfile.Visitor; // Use _this_ one!
+import org.apache.bcel.generic.*;
+import org.apache.bcel.verifier.*;
+import org.apache.bcel.verifier.exc.*;
+import java.util.HashMap;
+import java.util.HashSet;
+
+/**
+ * This PassVerifier verifies a class file according to
+ * pass 2 as described in The Java Virtual Machine
+ * Specification, 2nd edition.
+ * More detailed information is to be found at the do_verify()
+ * method's documentation.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ * @see #do_verify()
+ */
+public final class Pass2Verifier extends PassVerifier implements Constants{
+
+ /**
+ * The LocalVariableInfo instances used by Pass3bVerifier.
+ * localVariablesInfos[i] denotes the information for the
+ * local variables of method number i in the
+ * JavaClass this verifier operates on.
+ */
+ private LocalVariablesInfo[] localVariablesInfos;
+
+ /** The Verifier that created this. */
+ private Verifier myOwner;
+
+ /**
+ * Should only be instantiated by a Verifier.
+ *
+ * @see Verifier
+ */
+ public Pass2Verifier(Verifier owner){
+ myOwner = owner;
+ }
+
+ /**
+ * Returns a LocalVariablesInfo object containing information
+ * about the usage of the local variables in the Code attribute
+ * of the said method or <B>null</B> if the class file this
+ * Pass2Verifier operates on could not be pass-2-verified correctly.
+ * The method number method_nr is the method you get using
+ * <B>Repository.lookupClass(myOwner.getClassname()).getMethods()[method_nr];</B>.
+ * You should not add own information. Leave that to JustIce.
+ */
+ public LocalVariablesInfo getLocalVariablesInfo(int method_nr){
+ if (this.verify() != VerificationResult.VR_OK) return null; // It's cached, don't worry.
+ if (method_nr < 0 || method_nr >= localVariablesInfos.length){
+ throw new AssertionViolatedException("Method number out of range.");
+ }
+ return localVariablesInfos[method_nr];
+ }
+
+ /**
+ * Pass 2 is the pass where static properties of the
+ * class file are checked without looking into "Code"
+ * arrays of methods.
+ * This verification pass is usually invoked when
+ * a class is resolved; and it may be possible that
+ * this verification pass has to load in other classes
+ * such as superclasses or implemented interfaces.
+ * Therefore, Pass 1 is run on them.<BR>
+ * Note that most referenced classes are <B>not</B> loaded
+ * in for verification or for an existance check by this
+ * pass; only the syntactical correctness of their names
+ * and descriptors (a.k.a. signatures) is checked.<BR>
+ * Very few checks that conceptually belong here
+ * are delayed until pass 3a in JustIce. JustIce does
+ * not only check for syntactical correctness but also
+ * for semantical sanity - therefore it needs access to
+ * the "Code" array of methods in a few cases. Please
+ * see the pass 3a documentation, too.
+ *
+ * @see org.apache.bcel.verifier.statics.Pass3aVerifier
+ */
+ public VerificationResult do_verify(){
+ VerificationResult vr1 = myOwner.doPass1();
+ if (vr1.equals(VerificationResult.VR_OK)){
+
+ // For every method, we could have information about the local variables out of LocalVariableTable attributes of
+ // the Code attributes.
+ localVariablesInfos = new LocalVariablesInfo[Repository.lookupClass(myOwner.getClassName()).getMethods().length];
+
+ VerificationResult vr = VerificationResult.VR_OK; // default.
+ try{
+ constant_pool_entries_satisfy_static_constraints();
+ field_and_method_refs_are_valid();
+ every_class_has_an_accessible_superclass();
+ final_methods_are_not_overridden();
+ }
+ catch (ClassConstraintException cce){
+ vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, cce.getMessage());
+ }
+ return vr;
+ }
+ else
+ return VerificationResult.VR_NOTYET;
+ }
+
+ /**
+ * Ensures that every class has a super class and that
+ * <B>final</B> classes are not subclassed.
+ * This means, the class this Pass2Verifier operates
+ * on has proper super classes (transitively) up to
+ * java.lang.Object.
+ * The reason for really loading (and Pass1-verifying)
+ * all of those classes here is that we need them in
+ * Pass2 anyway to verify no final methods are overridden
+ * (that could be declared anywhere in the ancestor hierarchy).
+ *
+ * @throws ClassConstraintException otherwise.
+ */
+ private void every_class_has_an_accessible_superclass(){
+ HashSet hs = new HashSet(); // save class names to detect circular inheritance
+ JavaClass jc = Repository.lookupClass(myOwner.getClassName());
+ int supidx = -1;
+
+ while (supidx != 0){
+ supidx = jc.getSuperclassNameIndex();
+
+ if (supidx == 0){
+ if (jc != Repository.lookupClass(Type.OBJECT.getClassName())){
+ throw new ClassConstraintException("Superclass of '"+jc.getClassName()+"' missing but not "+Type.OBJECT.getClassName()+" itself!");
+ }
+ }
+ else{
+ String supername = jc.getSuperclassName();
+ if (! hs.add(supername)){ // If supername already is in the list
+ throw new ClassConstraintException("Circular superclass hierarchy detected.");
+ }
+ Verifier v = VerifierFactory.getVerifier(supername);
+ VerificationResult vr = v.doPass1();
+
+ if (vr != VerificationResult.VR_OK){
+ throw new ClassConstraintException("Could not load in ancestor class '"+supername+"'.");
+ }
+ jc = Repository.lookupClass(supername);
+
+ if (jc.isFinal()){
+ throw new ClassConstraintException("Ancestor class '"+supername+"' has the FINAL access modifier and must therefore not be subclassed.");
+ }
+ }
+ }
+ }
+
+ /**
+ * Ensures that <B>final</B> methods are not overridden.
+ * <B>Precondition to run this method:
+ * constant_pool_entries_satisfy_static_constraints() and
+ * every_class_has_an_accessible_superclass() have to be invoked before
+ * (in that order).</B>
+ *
+ * @throws ClassConstraintException otherwise.
+ * @see #constant_pool_entries_satisfy_static_constraints()
+ * @see #every_class_has_an_accessible_superclass()
+ */
+ private void final_methods_are_not_overridden(){
+ HashMap hashmap = new HashMap();
+ JavaClass jc = Repository.lookupClass(myOwner.getClassName());
+
+ int supidx = -1;
+ while (supidx != 0){
+ supidx = jc.getSuperclassNameIndex();
+
+ ConstantPoolGen cpg = new ConstantPoolGen(jc.getConstantPool());
+ Method[] methods = jc.getMethods();
+ for (int i=0; i<methods.length; i++){
+ String name_and_sig = (methods[i].getName()+methods[i].getSignature());
+
+ if (hashmap.containsKey(name_and_sig)){
+ if (methods[i].isFinal()){
+ throw new ClassConstraintException("Method '"+name_and_sig+"' in class '"+hashmap.get(name_and_sig)+"' overrides the final (not-overridable) definition in class '"+jc.getClassName()+"'.");
+ }
+ else{
+ if (!methods[i].isStatic()){ // static methods don't inherit
+ hashmap.put(name_and_sig, jc.getClassName());
+ }
+ }
+ }
+ else{
+ if (!methods[i].isStatic()){ // static methods don't inherit
+ hashmap.put(name_and_sig, jc.getClassName());
+ }
+ }
+ }
+
+ jc = Repository.lookupClass(jc.getSuperclassName()); // Well, for OBJECT this returns OBJECT so it works (could return anything but must not throw an Exception).
+ }
+
+ }
+
+ /**
+ * Ensures that the constant pool entries satisfy the static constraints
+ * as described in The Java Virtual Machine Specification, 2nd Edition.
+ *
+ * @throws ClassConstraintException otherwise.
+ */
+ private void constant_pool_entries_satisfy_static_constraints(){
+ // Most of the consistency is handled internally by BCEL; here
+ // we only have to verify if the indices of the constants point
+ // to constants of the appropriate type and such.
+ JavaClass jc = Repository.lookupClass(myOwner.getClassName());
+ new CPESSC_Visitor(jc); // constructor implicitely traverses jc
+ }
+
+ /**
+ * A Visitor class that ensures the constant pool satisfies the static
+ * constraints.
+ * The visitXXX() methods throw ClassConstraintException instances otherwise.
+ *
+ * @see #constant_pool_entries_satisfy_static_constraints()
+ */
+ private class CPESSC_Visitor extends org.apache.bcel.classfile.EmptyVisitor implements Visitor{
+ private Class CONST_Class;
+ private Class CONST_Fieldref;
+ private Class CONST_Methodref;
+ private Class CONST_InterfaceMethodref;
+ private Class CONST_String;
+ private Class CONST_Integer;
+ private Class CONST_Float;
+ private Class CONST_Long;
+ private Class CONST_Double;
+ private Class CONST_NameAndType;
+ private Class CONST_Utf8;
+
+ private final JavaClass jc;
+ private final ConstantPool cp; // ==jc.getConstantPool() -- only here to save typing work and computing power.
+ private final int cplen; // == cp.getLength() -- to save computing power.
+ private DescendingVisitor carrier;
+
+ private HashSet field_names = new HashSet();
+ private HashSet field_names_and_desc = new HashSet();
+ private HashSet method_names_and_desc = new HashSet();
+
+ private CPESSC_Visitor(JavaClass _jc){
+ jc = _jc;
+ cp = _jc.getConstantPool();
+ cplen = cp.getLength();
+
+ CONST_Class = org.apache.bcel.classfile.ConstantClass.class;
+ CONST_Fieldref = org.apache.bcel.classfile.ConstantFieldref.class;
+ CONST_Methodref = org.apache.bcel.classfile.ConstantMethodref.class;
+ CONST_InterfaceMethodref = org.apache.bcel.classfile.ConstantInterfaceMethodref.class;
+ CONST_String = org.apache.bcel.classfile.ConstantString.class;
+ CONST_Integer = org.apache.bcel.classfile.ConstantInteger.class;
+ CONST_Float = org.apache.bcel.classfile.ConstantFloat.class;
+ CONST_Long = org.apache.bcel.classfile.ConstantLong.class;
+ CONST_Double = org.apache.bcel.classfile.ConstantDouble.class;
+ CONST_NameAndType = org.apache.bcel.classfile.ConstantNameAndType.class;
+ CONST_Utf8 = org.apache.bcel.classfile.ConstantUtf8.class;
+
+ carrier = new DescendingVisitor(_jc, this);
+ carrier.visit();
+ }
+
+ private void checkIndex(Node referrer, int index, Class shouldbe){
+ if ((index < 0) || (index >= cplen)){
+ throw new ClassConstraintException("Invalid index '"+index+"' used by '"+tostring(referrer)+"'.");
+ }
+ Constant c = cp.getConstant(index);
+ if (! shouldbe.isInstance(c)){
+ String isnot = shouldbe.toString().substring(shouldbe.toString().lastIndexOf(".")+1); //Cut all before last "."
+ throw new ClassCastException("Illegal constant '"+tostring(c)+"' at index '"+index+"'. '"+tostring(referrer)+"' expects a '"+shouldbe+"'.");
+ }
+ }
+ ///////////////////////////////////////
+ // ClassFile structure (vmspec2 4.1) //
+ ///////////////////////////////////////
+ public void visitJavaClass(JavaClass obj){
+ Attribute[] atts = obj.getAttributes();
+ boolean foundSourceFile = false;
+ boolean foundInnerClasses = false;
+
+ // Is there an InnerClass referenced?
+ // This is a costly check; existing verifiers don't do it!
+ boolean hasInnerClass = new InnerClassDetector(jc).innerClassReferenced();
+
+ for (int i=0; i<atts.length; i++){
+ if ((! (atts[i] instanceof SourceFile)) &&
+ (! (atts[i] instanceof Deprecated)) &&
+ (! (atts[i] instanceof InnerClasses)) &&
+ (! (atts[i] instanceof Synthetic))){
+ addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of the ClassFile structure '"+tostring(obj)+"' is unknown and will therefore be ignored.");
+ }
+
+ if (atts[i] instanceof SourceFile){
+ if (foundSourceFile == false) foundSourceFile = true;
+ else throw new ClassConstraintException("A ClassFile structure (like '"+tostring(obj)+"') may have no more than one SourceFile attribute."); //vmspec2 4.7.7
+ }
+
+ if (atts[i] instanceof InnerClasses){
+ if (foundInnerClasses == false) foundInnerClasses = true;
+ else{
+ if (hasInnerClass){
+ throw new ClassConstraintException("A Classfile structure (like '"+tostring(obj)+"') must have exactly one InnerClasses attribute if at least one Inner Class is referenced (which is the case). More than one InnerClasses attribute was found.");
+ }
+ }
+ if (!hasInnerClass){
+ addMessage("No referenced Inner Class found, but InnerClasses attribute '"+tostring(atts[i])+"' found. Strongly suggest removal of that attribute.");
+ }
+ }
+
+ }
+ if (hasInnerClass && !foundInnerClasses){
+ //throw new ClassConstraintException("A Classfile structure (like '"+tostring(obj)+"') must have exactly one InnerClasses attribute if at least one Inner Class is referenced (which is the case). No InnerClasses attribute was found.");
+ //vmspec2, page 125 says it would be a constraint: but existing verifiers
+ //don't check it and javac doesn't satisfy it when it comes to anonymous
+ //inner classes
+ addMessage("A Classfile structure (like '"+tostring(obj)+"') must have exactly one InnerClasses attribute if at least one Inner Class is referenced (which is the case). No InnerClasses attribute was found.");
+ }
+ }
+ /////////////////////////////
+ // CONSTANTS (vmspec2 4.4) //
+ /////////////////////////////
+ public void visitConstantClass(ConstantClass obj){
+ if (obj.getTag() != Constants.CONSTANT_Class){
+ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
+ }
+ checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
+
+ }
+ public void visitConstantFieldref(ConstantFieldref obj){
+ if (obj.getTag() != Constants.CONSTANT_Fieldref){
+ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
+ }
+ checkIndex(obj, obj.getClassIndex(), CONST_Class);
+ checkIndex(obj, obj.getNameAndTypeIndex(), CONST_NameAndType);
+ }
+ public void visitConstantMethodref(ConstantMethodref obj){
+ if (obj.getTag() != Constants.CONSTANT_Methodref){
+ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
+ }
+ checkIndex(obj, obj.getClassIndex(), CONST_Class);
+ checkIndex(obj, obj.getNameAndTypeIndex(), CONST_NameAndType);
+ }
+ public void visitConstantInterfaceMethodref(ConstantInterfaceMethodref obj){
+ if (obj.getTag() != Constants.CONSTANT_InterfaceMethodref){
+ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
+ }
+ checkIndex(obj, obj.getClassIndex(), CONST_Class);
+ checkIndex(obj, obj.getNameAndTypeIndex(), CONST_NameAndType);
+ }
+ public void visitConstantString(ConstantString obj){
+ if (obj.getTag() != Constants.CONSTANT_String){
+ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
+ }
+ checkIndex(obj, obj.getStringIndex(), CONST_Utf8);
+ }
+ public void visitConstantInteger(ConstantInteger obj){
+ if (obj.getTag() != Constants.CONSTANT_Integer){
+ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
+ }
+ // no indices to check
+ }
+ public void visitConstantFloat(ConstantFloat obj){
+ if (obj.getTag() != Constants.CONSTANT_Float){
+ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
+ }
+ //no indices to check
+ }
+ public void visitConstantLong(ConstantLong obj){
+ if (obj.getTag() != Constants.CONSTANT_Long){
+ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
+ }
+ //no indices to check
+ }
+ public void visitConstantDouble(ConstantDouble obj){
+ if (obj.getTag() != Constants.CONSTANT_Double){
+ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
+ }
+ //no indices to check
+ }
+ public void visitConstantNameAndType(ConstantNameAndType obj){
+ if (obj.getTag() != Constants.CONSTANT_NameAndType){
+ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
+ }
+ checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
+ //checkIndex(obj, obj.getDescriptorIndex(), CONST_Utf8); //inconsistently named in BCEL, see below.
+ checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8);
+ }
+ public void visitConstantUtf8(ConstantUtf8 obj){
+ if (obj.getTag() != Constants.CONSTANT_Utf8){
+ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'.");
+ }
+ //no indices to check
+ }
+ //////////////////////////
+ // FIELDS (vmspec2 4.5) //
+ //////////////////////////
+ public void visitField(Field obj){
+
+ if (jc.isClass()){
+ int maxone=0;
+ if (obj.isPrivate()) maxone++;
+ if (obj.isProtected()) maxone++;
+ if (obj.isPublic()) maxone++;
+ if (maxone > 1){
+ throw new ClassConstraintException("Field '"+tostring(obj)+"' must only have at most one of its ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC modifiers set.");
+ }
+
+ if (obj.isFinal() && obj.isVolatile()){
+ throw new ClassConstraintException("Field '"+tostring(obj)+"' must only have at most one of its ACC_FINAL, ACC_VOLATILE modifiers set.");
+ }
+ }
+ else{ // isInterface!
+ if (!obj.isPublic()){
+ throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_PUBLIC modifier set but hasn't!");
+ }
+ if (!obj.isStatic()){
+ throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_STATIC modifier set but hasn't!");
+ }
+ if (!obj.isFinal()){
+ throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_FINAL modifier set but hasn't!");
+ }
+ }
+
+ if ((obj.getAccessFlags() & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_VOLATILE|ACC_TRANSIENT)) > 0){
+ addMessage("Field '"+tostring(obj)+"' has access flag(s) other than ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_VOLATILE, ACC_TRANSIENT set (ignored).");
+ }
+
+ checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
+
+ String name = obj.getName();
+ if (! validFieldName(name)){
+ throw new ClassConstraintException("Field '"+tostring(obj)+"' has illegal name '"+obj.getName()+"'.");
+ }
+
+ // A descriptor is often named signature in BCEL
+ checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8);
+
+ String sig = ((ConstantUtf8) (cp.getConstant(obj.getSignatureIndex()))).getBytes(); // Field or Method signature(=descriptor)
+
+ try{
+ Type t = Type.getType(sig);
+ }
+ catch (ClassFormatError cfe){ // sometimes BCEL is a little harsh describing exceptional situations.
+ throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'.");
+ }
+
+ String nameanddesc = (name+sig);
+ if (field_names_and_desc.contains(nameanddesc)){
+ throw new ClassConstraintException("No two fields (like '"+tostring(obj)+"') are allowed have same names and descriptors!");
+ }
+ if (field_names.contains(name)){
+ addMessage("More than one field of name '"+name+"' detected (but with different type descriptors). This is very unusual.");
+ }
+ field_names_and_desc.add(nameanddesc);
+ field_names.add(name);
+
+ Attribute[] atts = obj.getAttributes();
+ for (int i=0; i<atts.length; i++){
+ if ((! (atts[i] instanceof ConstantValue)) &&
+ (! (atts[i] instanceof Synthetic)) &&
+ (! (atts[i] instanceof Deprecated))){
+ addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Field '"+tostring(obj)+"' is unknown and will therefore be ignored.");
+ }
+ if (! (atts[i] instanceof ConstantValue)){
+ addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Field '"+tostring(obj)+"' is not a ConstantValue and is therefore only of use for debuggers and such.");
+ }
+ }
+ }
+ ///////////////////////////
+ // METHODS (vmspec2 4.6) //
+ ///////////////////////////
+ public void visitMethod(Method obj){
+
+ checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
+
+ String name = obj.getName();
+ if (! validMethodName(name, true)){
+ throw new ClassConstraintException("Method '"+tostring(obj)+"' has illegal name '"+name+"'.");
+ }
+
+ // A descriptor is often named signature in BCEL
+ checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8);
+
+ String sig = ((ConstantUtf8) (cp.getConstant(obj.getSignatureIndex()))).getBytes(); // Method's signature(=descriptor)
+
+ Type t;
+ Type[] ts; // needed below the try block.
+ try{
+ t = Type.getReturnType(sig);
+ ts = Type.getArgumentTypes(sig);
+ }
+ catch (ClassFormatError cfe){
+ // Well, BCEL sometimes is a little harsh describing exceptional situations.
+ throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by Method '"+tostring(obj)+"'.");
+ }
+
+ // Check if referenced objects exist.
+ Type act = t;
+ if (act instanceof ArrayType) act = ((ArrayType) act).getBasicType();
+ if (act instanceof ObjectType){
+ Verifier v = VerifierFactory.getVerifier( ((ObjectType) act).getClassName() );
+ VerificationResult vr = v.doPass1();
+ if (vr != VerificationResult.VR_OK) {
+ throw new ClassConstraintException("Method '"+tostring(obj)+"' has a return type that does not pass verification pass 1: '"+vr+"'.");
+ }
+ }
+
+ for (int i=0; i<ts.length; i++){
+ act = ts[i];
+ if (act instanceof ArrayType) act = ((ArrayType) act).getBasicType();
+ if (act instanceof ObjectType){
+ Verifier v = VerifierFactory.getVerifier( ((ObjectType) act).getClassName() );
+ VerificationResult vr = v.doPass1();
+ if (vr != VerificationResult.VR_OK) {
+ throw new ClassConstraintException("Method '"+tostring(obj)+"' has an argument type that does not pass verification pass 1: '"+vr+"'.");
+ }
+ }
+ }
+
+ // Nearly forgot this! Funny return values are allowed, but a non-empty arguments list makes a different method out of it!
+ if (name.equals(STATIC_INITIALIZER_NAME) && (ts.length != 0)){
+ throw new ClassConstraintException("Method '"+tostring(obj)+"' has illegal name '"+name+"'. It's name resembles the class or interface initialization method which it isn't because of its arguments (==descriptor).");
+ }
+
+ if (jc.isClass()){
+ int maxone=0;
+ if (obj.isPrivate()) maxone++;
+ if (obj.isProtected()) maxone++;
+ if (obj.isPublic()) maxone++;
+ if (maxone > 1){
+ throw new ClassConstraintException("Method '"+tostring(obj)+"' must only have at most one of its ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC modifiers set.");
+ }
+
+ if (obj.isAbstract()){
+ if (obj.isFinal()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_FINAL modifier set.");
+ if (obj.isNative()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_NATIVE modifier set.");
+ if (obj.isPrivate()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_PRIVATE modifier set.");
+ if (obj.isStatic()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_STATIC modifier set.");
+ if (obj.isStrictfp()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_STRICT modifier set.");
+ if (obj.isSynchronized()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_SYNCHRONIZED modifier set.");
+ }
+ }
+ else{ // isInterface!
+ if (!name.equals(STATIC_INITIALIZER_NAME)){//vmspec2, p.116, 2nd paragraph
+ if (!obj.isPublic()){
+ throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must have the ACC_PUBLIC modifier set but hasn't!");
+ }
+ if (!obj.isAbstract()){
+ throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must have the ACC_STATIC modifier set but hasn't!");
+ }
+ if ( obj.isPrivate() ||
+ obj.isProtected() ||
+ obj.isStatic() ||
+ obj.isFinal() ||
+ obj.isSynchronized() ||
+ obj.isNative() ||
+ obj.isStrictfp() ){
+ throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must not have any of the ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT, ACC_STRICT modifiers set.");
+ }
+ }
+ }
+
+ // A specific instance initialization method... (vmspec2,Page 116).
+ if (name.equals(CONSTRUCTOR_NAME)){
+ //..may have at most one of ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC set: is checked above.
+ //..may also have ACC_STRICT set, but none of the other flags in table 4.5 (vmspec2, page 115)
+ if ( obj.isStatic() ||
+ obj.isFinal() ||
+ obj.isSynchronized() ||
+ obj.isNative() ||
+ obj.isAbstract() ){
+ throw new ClassConstraintException("Instance initialization method '"+tostring(obj)+"' must not have any of the ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT modifiers set.");
+ }
+ }
+
+ // Class and interface initialization methods...
+ if (name.equals(STATIC_INITIALIZER_NAME)){
+ if ((obj.getAccessFlags() & (~ACC_STRICT)) > 0){
+ addMessage("Class or interface initialization method '"+tostring(obj)+"' has superfluous access modifier(s) set: everything but ACC_STRICT is ignored.");
+ }
+ if (obj.isAbstract()){
+ throw new ClassConstraintException("Class or interface initialization method '"+tostring(obj)+"' must not be abstract. This contradicts the Java Language Specification, Second Edition (which omits this constraint) but is common practice of existing verifiers.");
+ }
+ }
+
+ if ((obj.getAccessFlags() & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_SYNCHRONIZED|ACC_NATIVE|ACC_ABSTRACT|ACC_STRICT)) > 0){
+ addMessage("Method '"+tostring(obj)+"' has access flag(s) other than ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT, ACC_STRICT set (ignored).");
+ }
+
+ String nameanddesc = (name+sig);
+ if (method_names_and_desc.contains(nameanddesc)){
+ throw new ClassConstraintException("No two methods (like '"+tostring(obj)+"') are allowed have same names and desciptors!");
+ }
+ method_names_and_desc.add(nameanddesc);
+
+ Attribute[] atts = obj.getAttributes();
+ int num_code_atts = 0;
+ for (int i=0; i<atts.length; i++){
+ if ((! (atts[i] instanceof Code)) &&
+ (! (atts[i] instanceof ExceptionTable)) &&
+ (! (atts[i] instanceof Synthetic)) &&
+ (! (atts[i] instanceof Deprecated))){
+ addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Method '"+tostring(obj)+"' is unknown and will therefore be ignored.");
+ }
+ if ((! (atts[i] instanceof Code)) &&
+ (! (atts[i] instanceof ExceptionTable))){
+ addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Method '"+tostring(obj)+"' is neither Code nor Exceptions and is therefore only of use for debuggers and such.");
+ }
+ if ((atts[i] instanceof Code) && (obj.isNative() || obj.isAbstract())){
+ throw new ClassConstraintException("Native or abstract methods like '"+tostring(obj)+"' must not have a Code attribute like '"+tostring(atts[i])+"'."); //vmspec2 page120, 4.7.3
+ }
+ if (atts[i] instanceof Code) num_code_atts++;
+ }
+ if ( !obj.isNative() && !obj.isAbstract() && num_code_atts != 1){
+ throw new ClassConstraintException("Non-native, non-abstract methods like '"+tostring(obj)+"' must have exactly one Code attribute (found: "+num_code_atts+").");
+ }
+ }
+ ///////////////////////////////////////////////////////
+ // ClassFile-structure-ATTRIBUTES (vmspec2 4.1, 4.7) //
+ ///////////////////////////////////////////////////////
+ public void visitSourceFile(SourceFile obj){//vmspec2 4.7.7
+
+ // zero or one SourceFile attr per ClassFile: see visitJavaClass()
+
+ checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
+
+ String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes();
+ if (! name.equals("SourceFile")){
+ throw new ClassConstraintException("The SourceFile attribute '"+tostring(obj)+"' is not correctly named 'SourceFile' but '"+name+"'.");
+ }
+
+ checkIndex(obj, obj.getSourceFileIndex(), CONST_Utf8);
+
+ String sourcefilename = ((ConstantUtf8) cp.getConstant(obj.getSourceFileIndex())).getBytes(); //==obj.getSourceFileName() ?
+ String sourcefilenamelc = sourcefilename.toLowerCase();
+
+ if ( (sourcefilename.indexOf('/') != -1) ||
+ (sourcefilename.indexOf('\\') != -1) ||
+ (sourcefilename.indexOf(':') != -1) ||
+ (sourcefilenamelc.lastIndexOf(".java") == -1) ){
+ addMessage("SourceFile attribute '"+tostring(obj)+"' has a funny name: remember not to confuse certain parsers working on javap's output. Also, this name ('"+sourcefilename+"') is considered an unqualified (simple) file name only.");
+ }
+ }
+ public void visitDeprecated(Deprecated obj){//vmspec2 4.7.10
+ checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
+
+ String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes();
+ if (! name.equals("Deprecated")){
+ throw new ClassConstraintException("The Deprecated attribute '"+tostring(obj)+"' is not correctly named 'Deprecated' but '"+name+"'.");
+ }
+ }
+ public void visitSynthetic(Synthetic obj){//vmspec2 4.7.6
+ checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
+ String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes();
+ if (! name.equals("Synthetic")){
+ throw new ClassConstraintException("The Synthetic attribute '"+tostring(obj)+"' is not correctly named 'Synthetic' but '"+name+"'.");
+ }
+ }
+ public void visitInnerClasses(InnerClasses obj){//vmspec2 4.7.5
+
+ // exactly one InnerClasses attr per ClassFile if some inner class is refernced: see visitJavaClass()
+
+ checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
+
+ String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes();
+ if (! name.equals("InnerClasses")){
+ throw new ClassConstraintException("The InnerClasses attribute '"+tostring(obj)+"' is not correctly named 'InnerClasses' but '"+name+"'.");
+ }
+
+ InnerClass[] ics = obj.getInnerClasses();
+
+ for (int i=0; i<ics.length; i++){
+ checkIndex(obj, ics[i].getInnerClassIndex(), CONST_Class);
+ int outer_idx = ics[i].getOuterClassIndex();
+ if (outer_idx != 0){
+ checkIndex(obj, outer_idx, CONST_Class);
+ }
+ int innername_idx = ics[i].getInnerNameIndex();
+ if (innername_idx != 0){
+ checkIndex(obj, innername_idx, CONST_Utf8);
+ }
+ int acc = ics[i].getInnerAccessFlags();
+ acc = acc & (~ (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT));
+ if (acc != 0){
+ addMessage("Unknown access flag for inner class '"+tostring(ics[i])+"' set (InnerClasses attribute '"+tostring(obj)+"').");
+ }
+ }
+ // Semantical consistency is not yet checked by Sun, see vmspec2 4.7.5.
+ // [marked TODO in JustIce]
+ }
+ ////////////////////////////////////////////////////////
+ // field_info-structure-ATTRIBUTES (vmspec2 4.5, 4.7) //
+ ////////////////////////////////////////////////////////
+ public void visitConstantValue(ConstantValue obj){//vmspec2 4.7.2
+ // Despite its name, this really is an Attribute,
+ // not a constant!
+ checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
+
+ String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes();
+ if (! name.equals("ConstantValue")){
+ throw new ClassConstraintException("The ConstantValue attribute '"+tostring(obj)+"' is not correctly named 'ConstantValue' but '"+name+"'.");
+ }
+
+ Object pred = carrier.predecessor();
+ if (pred instanceof Field){ //ConstantValue attributes are quite senseless if the predecessor is not a field.
+ Field f = (Field) pred;
+ // Field constraints have been checked before -- so we are safe using their type information.
+ Type field_type = Type.getType(((ConstantUtf8) (cp.getConstant(f.getSignatureIndex()))).getBytes());
+
+ int index = obj.getConstantValueIndex();
+ if ((index < 0) || (index >= cplen)){
+ throw new ClassConstraintException("Invalid index '"+index+"' used by '"+tostring(obj)+"'.");
+ }
+ Constant c = cp.getConstant(index);
+
+ if (CONST_Long.isInstance(c) && field_type.equals(Type.LONG)){
+ return;
+ }
+ if (CONST_Float.isInstance(c) && field_type.equals(Type.FLOAT)){
+ return;
+ }
+ if (CONST_Double.isInstance(c) && field_type.equals(Type.DOUBLE)){
+ return;
+ }
+ if (CONST_Integer.isInstance(c) && (field_type.equals(Type.INT) || field_type.equals(Type.SHORT) || field_type.equals(Type.CHAR) || field_type.equals(Type.BYTE) || field_type.equals(Type.BOOLEAN))){
+ return;
+ }
+ if (CONST_String.isInstance(c) && field_type.equals(Type.STRING)){
+ return;
+ }
+
+ throw new ClassConstraintException("Illegal type of ConstantValue '"+obj+"' embedding Constant '"+c+"'. It is referenced by field '"+tostring(f)+"' expecting a different type: '"+field_type+"'.");
+ }
+ }
+ // SYNTHETIC: see above
+ // DEPRECATED: see above
+ /////////////////////////////////////////////////////////
+ // method_info-structure-ATTRIBUTES (vmspec2 4.6, 4.7) //
+ /////////////////////////////////////////////////////////
+ public void visitCode(Code obj){//vmspec2 4.7.3
+ // No code attribute allowed for native or abstract methods: see visitMethod(Method).
+ // Code array constraints are checked in Pass3 (3a and 3b).
+
+ checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
+
+ String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes();
+ if (! name.equals("Code")){
+ throw new ClassConstraintException("The Code attribute '"+tostring(obj)+"' is not correctly named 'Code' but '"+name+"'.");
+ }
+
+ Method m = null; // satisfy compiler
+ if (!(carrier.predecessor() instanceof Method)){
+ addMessage("Code attribute '"+tostring(obj)+"' is not declared in a method_info structure but in '"+carrier.predecessor()+"'. Ignored.");
+ return;
+ }
+ else{
+ m = (Method) carrier.predecessor(); // we can assume this method was visited before;
+ // i.e. the data consistency was verified.
+ }
+
+ if (obj.getCode().length == 0){
+ throw new ClassConstraintException("Code array of Code attribute '"+tostring(obj)+"' (method '"+m+"') must not be empty.");
+ }
+
+ //In JustIce, the check for correct offsets into the code array is delayed to Pass 3a.
+ CodeException[] exc_table = obj.getExceptionTable();
+ for (int i=0; i<exc_table.length; i++){
+ int exc_index = exc_table[i].getCatchType();
+ if (exc_index != 0){ // if 0, it catches all Throwables
+ checkIndex(obj, exc_index, CONST_Class);
+ ConstantClass cc = (ConstantClass) (cp.getConstant(exc_index));
+ checkIndex(cc, cc.getNameIndex(), CONST_Utf8); // cannot be sure this ConstantClass has already been visited (checked)!
+ String cname = ((ConstantUtf8) cp.getConstant(cc.getNameIndex())).getBytes().replace('/','.');
+
+ Verifier v = VerifierFactory.getVerifier(cname);
+ VerificationResult vr = v.doPass1();
+
+ if (vr != VerificationResult.VR_OK){
+ throw new ClassConstraintException("Code attribute '"+tostring(obj)+"' (method '"+m+"') has an exception_table entry '"+tostring(exc_table[i])+"' that references '"+cname+"' as an Exception but it does not pass verification pass 1: "+vr);
+ }
+ else{
+ // We cannot safely trust any other "instanceof" mechanism. We need to transitively verify
+ // the ancestor hierarchy.
+ JavaClass e = Repository.lookupClass(cname);
+ JavaClass t = Repository.lookupClass(Type.THROWABLE.getClassName());
+ JavaClass o = Repository.lookupClass(Type.OBJECT.getClassName());
+ while (e != o){
+ if (e == t) break; // It's a subclass of Throwable, OKAY, leave.
+
+ v = VerifierFactory.getVerifier(e.getSuperclassName());
+ vr = v.doPass1();
+ if (vr != VerificationResult.VR_OK){
+ throw new ClassConstraintException("Code attribute '"+tostring(obj)+"' (method '"+m+"') has an exception_table entry '"+tostring(exc_table[i])+"' that references '"+cname+"' as an Exception but '"+e.getSuperclassName()+"' in the ancestor hierachy does not pass verification pass 1: "+vr);
+ }
+ else{
+ e = Repository.lookupClass(e.getSuperclassName());
+ }
+ }
+ if (e != t) throw new ClassConstraintException("Code attribute '"+tostring(obj)+"' (method '"+m+"') has an exception_table entry '"+tostring(exc_table[i])+"' that references '"+cname+"' as an Exception but it is not a subclass of '"+t.getClassName()+"'.");
+ }
+ }
+ }
+
+ // Create object for local variables information
+ // This is highly unelegant due to usage of the Visitor pattern.
+ // TODO: rework it.
+ int method_number = -1;
+ Method[] ms = Repository.lookupClass(myOwner.getClassName()).getMethods();
+ for (int mn=0; mn<ms.length; mn++){
+ if (m == ms[mn]){
+ method_number = mn;
+ break;
+ }
+ }
+ if (method_number < 0){ // Mmmmh. Can we be sure BCEL does not sometimes instantiate new objects?
+ throw new AssertionViolatedException("Could not find a known BCEL Method object in the corresponding BCEL JavaClass object.");
+ }
+ localVariablesInfos[method_number] = new LocalVariablesInfo(obj.getMaxLocals());
+
+ int num_of_lvt_attribs = 0;
+ // Now iterate through the attributes the Code attribute has.
+ Attribute[] atts = obj.getAttributes();
+ for (int a=0; a<atts.length; a++){
+ if ((! (atts[a] instanceof LineNumberTable)) &&
+ (! (atts[a] instanceof LocalVariableTable))){
+ addMessage("Attribute '"+tostring(atts[a])+"' as an attribute of Code attribute '"+tostring(obj)+"' (method '"+m+"') is unknown and will therefore be ignored.");
+ }
+ else{// LineNumberTable or LocalVariableTable
+ addMessage("Attribute '"+tostring(atts[a])+"' as an attribute of Code attribute '"+tostring(obj)+"' (method '"+m+"') will effectively be ignored and is only useful for debuggers and such.");
+ }
+
+ //LocalVariableTable check (partially delayed to Pass3a).
+ //Here because its easier to collect the information of the
+ //(possibly more than one) LocalVariableTables belonging to
+ //one certain Code attribute.
+ if (atts[a] instanceof LocalVariableTable){ // checks conforming to vmspec2 4.7.9
+
+ LocalVariableTable lvt = (LocalVariableTable) atts[a];
+
+ checkIndex(lvt, lvt.getNameIndex(), CONST_Utf8);
+
+ String lvtname = ((ConstantUtf8) cp.getConstant(lvt.getNameIndex())).getBytes();
+ if (! lvtname.equals("LocalVariableTable")){
+ throw new ClassConstraintException("The LocalVariableTable attribute '"+tostring(lvt)+"' is not correctly named 'LocalVariableTable' but '"+lvtname+"'.");
+ }
+
+ Code code = obj;
+ int max_locals = code.getMaxLocals();
+
+ //In JustIce, the check for correct offsets into the code array is delayed to Pass 3a.
+ LocalVariable[] localvariables = lvt.getLocalVariableTable();
+
+ for (int i=0; i<localvariables.length; i++){
+ checkIndex(lvt, localvariables[i].getNameIndex(), CONST_Utf8);
+ String localname = ((ConstantUtf8) cp.getConstant(localvariables[i].getNameIndex())).getBytes();
+ if (!validJavaIdentifier(localname)){
+ throw new ClassConstraintException("LocalVariableTable '"+tostring(lvt)+"' references a local variable by the name '"+localname+"' which is not a legal Java simple name.");
+ }
+
+ checkIndex(lvt, localvariables[i].getSignatureIndex(), CONST_Utf8);
+ String localsig = ((ConstantUtf8) (cp.getConstant(localvariables[i].getSignatureIndex()))).getBytes(); // Local signature(=descriptor)
+ Type t;
+ try{
+ t = Type.getType(localsig);
+ }
+ catch (ClassFormatError cfe){ // sometimes BCEL is a little harsh describing exceptional situations.
+ throw new ClassConstraintException("Illegal descriptor (==signature) '"+localsig+"' used by LocalVariable '"+tostring(localvariables[i])+"' referenced by '"+tostring(lvt)+"'.");
+ }
+ int localindex = localvariables[i].getIndex();
+ if ( ( (t==Type.LONG || t==Type.DOUBLE)? localindex+1:localindex) >= code.getMaxLocals()){
+ throw new ClassConstraintException("LocalVariableTable attribute '"+tostring(lvt)+"' references a LocalVariable '"+tostring(localvariables[i])+"' with an index that exceeds the surrounding Code attribute's max_locals value of '"+code.getMaxLocals()+"'.");
+ }
+
+ try{
+ localVariablesInfos[method_number].add(localindex, localname, localvariables[i].getStartPC(), localvariables[i].getLength(), t);
+ }
+ catch(LocalVariableInfoInconsistentException lviie){
+ throw new ClassConstraintException("Conflicting information in LocalVariableTable '"+tostring(lvt)+"' found in Code attribute '"+tostring(obj)+"' (method '"+tostring(m)+"'). "+lviie.getMessage());
+ }
+ }// for all local variables localvariables[i] in the LocalVariableTable attribute atts[a] END
+
+ num_of_lvt_attribs++;
+ if (num_of_lvt_attribs > obj.getMaxLocals()){
+ throw new ClassConstraintException("Number of LocalVariableTable attributes of Code attribute '"+tostring(obj)+"' (method '"+tostring(m)+"') exceeds number of local variable slots '"+obj.getMaxLocals()+"' ('There may be no more than one LocalVariableTable attribute per local variable in the Code attribute.').");
+ }
+ }// if atts[a] instanceof LocalVariableTable END
+ }// for all attributes atts[a] END
+ }// visitCode(Code) END
+
+ public void visitExceptionTable(ExceptionTable obj){//vmspec2 4.7.4
+ // incorrectly named, it's the Exceptions attribute (vmspec2 4.7.4)
+ checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
+
+ String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes();
+ if (! name.equals("Exceptions")){
+ throw new ClassConstraintException("The Exceptions attribute '"+tostring(obj)+"' is not correctly named 'Exceptions' but '"+name+"'.");
+ }
+
+ int[] exc_indices = obj.getExceptionIndexTable();
+
+ for (int i=0; i<exc_indices.length; i++){
+ checkIndex(obj, exc_indices[i], CONST_Class);
+
+ ConstantClass cc = (ConstantClass) (cp.getConstant(exc_indices[i]));
+ checkIndex(cc, cc.getNameIndex(), CONST_Utf8); // cannot be sure this ConstantClass has already been visited (checked)!
+ String cname = ((ConstantUtf8) cp.getConstant(cc.getNameIndex())).getBytes().replace('/','.'); //convert internal notation on-the-fly to external notation
+
+ Verifier v = VerifierFactory.getVerifier(cname);
+ VerificationResult vr = v.doPass1();
+
+ if (vr != VerificationResult.VR_OK){
+ throw new ClassConstraintException("Exceptions attribute '"+tostring(obj)+"' references '"+cname+"' as an Exception but it does not pass verification pass 1: "+vr);
+ }
+ else{
+ // We cannot safely trust any other "instanceof" mechanism. We need to transitively verify
+ // the ancestor hierarchy.
+ JavaClass e = Repository.lookupClass(cname);
+ JavaClass t = Repository.lookupClass(Type.THROWABLE.getClassName());
+ JavaClass o = Repository.lookupClass(Type.OBJECT.getClassName());
+ while (e != o){
+ if (e == t) break; // It's a subclass of Throwable, OKAY, leave.
+
+ v = VerifierFactory.getVerifier(e.getSuperclassName());
+ vr = v.doPass1();
+ if (vr != VerificationResult.VR_OK){
+ throw new ClassConstraintException("Exceptions attribute '"+tostring(obj)+"' references '"+cname+"' as an Exception but '"+e.getSuperclassName()+"' in the ancestor hierachy does not pass verification pass 1: "+vr);
+ }
+ else{
+ e = Repository.lookupClass(e.getSuperclassName());
+ }
+ }
+ if (e != t) throw new ClassConstraintException("Exceptions attribute '"+tostring(obj)+"' references '"+cname+"' as an Exception but it is not a subclass of '"+t.getClassName()+"'.");
+ }
+ }
+ }
+ // SYNTHETIC: see above
+ // DEPRECATED: see above
+ //////////////////////////////////////////////////////////////
+ // code_attribute-structure-ATTRIBUTES (vmspec2 4.7.3, 4.7) //
+ //////////////////////////////////////////////////////////////
+ public void visitLineNumberTable(LineNumberTable obj){//vmspec2 4.7.8
+ checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
+
+ String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes();
+ if (! name.equals("LineNumberTable")){
+ throw new ClassConstraintException("The LineNumberTable attribute '"+tostring(obj)+"' is not correctly named 'LineNumberTable' but '"+name+"'.");
+ }
+
+ //In JustIce,this check is delayed to Pass 3a.
+ //LineNumber[] linenumbers = obj.getLineNumberTable();
+ // ...validity check...
+
+ }
+ public void visitLocalVariableTable(LocalVariableTable obj){//vmspec2 4.7.9
+ //In JustIce,this check is partially delayed to Pass 3a.
+ //The other part can be found in the visitCode(Code) method.
+ }
+ ////////////////////////////////////////////////////
+ // MISC-structure-ATTRIBUTES (vmspec2 4.7.1, 4.7) //
+ ////////////////////////////////////////////////////
+ public void visitUnknown(Unknown obj){//vmspec2 4.7.1
+ // Represents an unknown attribute.
+ checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
+
+ // Maybe only misnamed? Give a (warning) message.
+ addMessage("Unknown attribute '"+tostring(obj)+"'. This attribute is not known in any context!");
+ }
+ //////////
+ // BCEL //
+ //////////
+ public void visitLocalVariable(LocalVariable obj){
+ // This does not represent an Attribute but is only
+ // related to internal BCEL data representation.
+
+ // see visitLocalVariableTable(LocalVariableTable)
+ }
+ public void visitCodeException(CodeException obj){
+ // Code constraints are checked in Pass3 (3a and 3b).
+ // This does not represent an Attribute but is only
+ // related to internal BCEL data representation.
+
+ // see visitCode(Code)
+ }
+ public void visitConstantPool(ConstantPool obj){
+ // No need to. We're piggybacked by the DescendingVisitor.
+ // This does not represent an Attribute but is only
+ // related to internal BCEL data representation.
+ }
+ public void visitInnerClass(InnerClass obj){
+ // This does not represent an Attribute but is only
+ // related to internal BCEL data representation.
+ }
+ public void visitLineNumber(LineNumber obj){
+ // This does not represent an Attribute but is only
+ // related to internal BCEL data representation.
+
+ // see visitLineNumberTable(LineNumberTable)
+ }
+ }
+
+ /**
+ * Ensures that the ConstantCP-subclassed entries of the constant
+ * pool are valid. According to "Yellin: Low Level Security in Java",
+ * this method does not verify the existence of referenced entities
+ * (such as classes) but only the formal correctness (such as well-formed
+ * signatures).
+ * The visitXXX() methods throw ClassConstraintException instances otherwise.
+ * <B>Precondition: index-style cross referencing in the constant
+ * pool must be valid. Simply invoke constant_pool_entries_satisfy_static_constraints()
+ * before.</B>
+ *
+ * @throws ClassConstraintException otherwise.
+ * @see #constant_pool_entries_satisfy_static_constraints()
+ */
+ private void field_and_method_refs_are_valid(){
+ JavaClass jc = Repository.lookupClass(myOwner.getClassName());
+ DescendingVisitor v = new DescendingVisitor(jc, new FAMRAV_Visitor(jc));
+ v.visit();
+ }
+
+ /**
+ * A Visitor class that ensures the ConstantCP-subclassed entries
+ * of the constant pool are valid.
+ * <B>Precondition: index-style cross referencing in the constant
+ * pool must be valid.</B>
+ *
+ * @see #constant_pool_entries_satisfy_static_constraints()
+ * @see org.apache.bcel.classfile.ConstantCP
+ */
+ private class FAMRAV_Visitor extends EmptyVisitor implements Visitor{
+ private final JavaClass jc;
+ private final ConstantPool cp; // ==jc.getConstantPool() -- only here to save typing work.
+ private FAMRAV_Visitor(JavaClass _jc){
+ jc = _jc;
+ cp = _jc.getConstantPool();
+ }
+
+ public void visitConstantFieldref(ConstantFieldref obj){
+ if (obj.getTag() != Constants.CONSTANT_Fieldref){
+ throw new ClassConstraintException("ConstantFieldref '"+tostring(obj)+"' has wrong tag!");
+ }
+ int name_and_type_index = obj.getNameAndTypeIndex();
+ ConstantNameAndType cnat = (ConstantNameAndType) (cp.getConstant(name_and_type_index));
+ String name = ((ConstantUtf8) (cp.getConstant(cnat.getNameIndex()))).getBytes(); // Field or Method name
+ if (!validFieldName(name)){
+ throw new ClassConstraintException("Invalid field name '"+name+"' referenced by '"+tostring(obj)+"'.");
+ }
+
+ int class_index = obj.getClassIndex();
+ ConstantClass cc = (ConstantClass) (cp.getConstant(class_index));
+ String className = ((ConstantUtf8) (cp.getConstant(cc.getNameIndex()))).getBytes(); // Class Name in internal form
+ if (! validClassName(className)){
+ throw new ClassConstraintException("Illegal class name '"+className+"' used by '"+tostring(obj)+"'.");
+ }
+
+ String sig = ((ConstantUtf8) (cp.getConstant(cnat.getSignatureIndex()))).getBytes(); // Field or Method signature(=descriptor)
+
+ try{
+ Type t = Type.getType(sig);
+ }
+ catch (ClassFormatError cfe){
+ // Well, BCEL sometimes is a little harsh describing exceptional situations.
+ throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'.");
+ }
+ }
+
+ public void visitConstantMethodref(ConstantMethodref obj){
+ if (obj.getTag() != Constants.CONSTANT_Methodref){
+ throw new ClassConstraintException("ConstantMethodref '"+tostring(obj)+"' has wrong tag!");
+ }
+ int name_and_type_index = obj.getNameAndTypeIndex();
+ ConstantNameAndType cnat = (ConstantNameAndType) (cp.getConstant(name_and_type_index));
+ String name = ((ConstantUtf8) (cp.getConstant(cnat.getNameIndex()))).getBytes(); // Field or Method name
+ if (!validClassMethodName(name)){
+ throw new ClassConstraintException("Invalid (non-interface) method name '"+name+"' referenced by '"+tostring(obj)+"'.");
+ }
+
+ int class_index = obj.getClassIndex();
+ ConstantClass cc = (ConstantClass) (cp.getConstant(class_index));
+ String className = ((ConstantUtf8) (cp.getConstant(cc.getNameIndex()))).getBytes(); // Class Name in internal form
+ if (! validClassName(className)){
+ throw new ClassConstraintException("Illegal class name '"+className+"' used by '"+tostring(obj)+"'.");
+ }
+
+ String sig = ((ConstantUtf8) (cp.getConstant(cnat.getSignatureIndex()))).getBytes(); // Field or Method signature(=descriptor)
+
+ try{
+ Type t = Type.getReturnType(sig);
+ Type[] ts = Type.getArgumentTypes(sig);
+ if ( name.equals(CONSTRUCTOR_NAME) && (t != Type.VOID) ){
+ throw new ClassConstraintException("Instance initialization method must have VOID return type.");
+ }
+ }
+ catch (ClassFormatError cfe){
+ // Well, BCEL sometimes is a little harsh describing exceptional situations.
+ throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'.");
+ }
+ }
+
+ public void visitConstantInterfaceMethodref(ConstantInterfaceMethodref obj){
+ if (obj.getTag() != Constants.CONSTANT_InterfaceMethodref){
+ throw new ClassConstraintException("ConstantInterfaceMethodref '"+tostring(obj)+"' has wrong tag!");
+ }
+ int name_and_type_index = obj.getNameAndTypeIndex();
+ ConstantNameAndType cnat = (ConstantNameAndType) (cp.getConstant(name_and_type_index));
+ String name = ((ConstantUtf8) (cp.getConstant(cnat.getNameIndex()))).getBytes(); // Field or Method name
+ if (!validInterfaceMethodName(name)){
+ throw new ClassConstraintException("Invalid (interface) method name '"+name+"' referenced by '"+tostring(obj)+"'.");
+ }
+
+ int class_index = obj.getClassIndex();
+ ConstantClass cc = (ConstantClass) (cp.getConstant(class_index));
+ String className = ((ConstantUtf8) (cp.getConstant(cc.getNameIndex()))).getBytes(); // Class Name in internal form
+ if (! validClassName(className)){
+ throw new ClassConstraintException("Illegal class name '"+className+"' used by '"+tostring(obj)+"'.");
+ }
+
+ String sig = ((ConstantUtf8) (cp.getConstant(cnat.getSignatureIndex()))).getBytes(); // Field or Method signature(=descriptor)
+
+ try{
+ Type t = Type.getReturnType(sig);
+ Type[] ts = Type.getArgumentTypes(sig);
+ if ( name.equals(STATIC_INITIALIZER_NAME) && (t != Type.VOID) ){
+ addMessage("Class or interface initialization method '"+STATIC_INITIALIZER_NAME+"' usually has VOID return type instead of '"+t+"'. Note this is really not a requirement of The Java Virtual Machine Specification, Second Edition.");
+ }
+ }
+ catch (ClassFormatError cfe){
+ // Well, BCEL sometimes is a little harsh describing exceptional situations.
+ throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'.");
+ }
+
+ }
+
+ }
+
+ /**
+ * This method returns true if and only if the supplied String
+ * represents a valid Java class name.
+ */
+ private static final boolean validClassName(String name){
+ // Are there restrictions?
+ return true;
+ }
+ /**
+ * This method returns true if and only if the supplied String
+ * represents a valid method name.
+ * This is basically the same as a valid identifier name in the
+ * Java programming language, but the special name for
+ * the instance initialization method is allowed and the special name
+ * for the class/interface initialization method may be allowed.
+ */
+ private static boolean validMethodName(String name, boolean allowStaticInit){
+ if (validJavaLangMethodName(name)) return true;
+
+ if (allowStaticInit){
+ return (name.equals(CONSTRUCTOR_NAME) || name.equals(STATIC_INITIALIZER_NAME));
+ }
+ else{
+ return name.equals(CONSTRUCTOR_NAME);
+ }
+ }
+
+ /**
+ * This method returns true if and only if the supplied String
+ * represents a valid method name that may be referenced by
+ * ConstantMethodref objects.
+ */
+ private static boolean validClassMethodName(String name){
+ return validMethodName(name, false);
+ }
+
+ /**
+ * This method returns true if and only if the supplied String
+ * represents a valid Java programming language method name stored as a simple
+ * (non-qualified) name.
+ * Conforming to: The Java Virtual Machine Specification, Second Edition, §2.7, §2.7.1, §2.2.
+ */
+ private static boolean validJavaLangMethodName(String name){
+ if (!Character.isJavaIdentifierStart(name.charAt(0))) return false;
+
+ for (int i=1; i<name.length(); i++){
+ if (!Character.isJavaIdentifierPart(name.charAt(i))) return false;
+ }
+ return true;
+ }
+
+ /**
+ * This method returns true if and only if the supplied String
+ * represents a valid Java interface method name that may be
+ * referenced by ConstantInterfaceMethodref objects.
+ */
+ private static boolean validInterfaceMethodName(String name){
+ // I guess we should assume special names forbidden here.
+ if (name.startsWith("<")) return false;
+ return validJavaLangMethodName(name);
+ }
+
+ /**
+ * This method returns true if and only if the supplied String
+ * represents a valid Java identifier (so-called simple name).
+ */
+ private static boolean validJavaIdentifier(String name){
+ // vmspec2 2.7, vmspec2 2.2
+ if (!Character.isJavaIdentifierStart(name.charAt(0))) return false;
+
+ for (int i=1; i<name.length(); i++){
+ if (!Character.isJavaIdentifierPart(name.charAt(i))) return false;
+ }
+ return true;
+ }
+
+ /**
+ * This method returns true if and only if the supplied String
+ * represents a valid Java field name.
+ */
+ private static boolean validFieldName(String name){
+ // vmspec2 2.7, vmspec2 2.2
+ return validJavaIdentifier(name);
+ }
+
+ /**
+ * This class serves for finding out if a given JavaClass' ConstantPool
+ * references an Inner Class.
+ * The Java Virtual Machine Specification, Second Edition is not very precise
+ * about when an "InnerClasses" attribute has to appear. However, it states that
+ * there has to be exactly one InnerClasses attribute in the ClassFile structure
+ * if the constant pool of a class or interface refers to any class or interface
+ * "that is not a member of a package". Sun does not mean "member of the default
+ * package". In "Inner Classes Specification" they point out how a "bytecode name"
+ * is derived so one has to deduce what a class name of a class "that is not a
+ * member of a package" looks like: there is at least one character in the byte-
+ * code name that cannot be part of a legal Java Language Class name (and not equal
+ * to '/'). This assumption is wrong as the delimiter is '$' for which
+ * Character.isJavaIdentifierPart() == true.
+ * Hence, you really run into trouble if you have a toplevel class called
+ * "A$XXX" and another toplevel class called "A" with in inner class called "XXX".
+ * JustIce cannot repair this; please note that existing verifiers at this
+ * time even fail to detect missing InnerClasses attributes in pass 2.
+ */
+ private class InnerClassDetector extends EmptyVisitor{
+ private boolean hasInnerClass = false;
+ private JavaClass jc;
+ private ConstantPool cp;
+ private InnerClassDetector(){} // Don't use.
+ /** Constructs an InnerClassDetector working on the JavaClass _jc. */
+ public InnerClassDetector(JavaClass _jc){
+ jc = _jc;
+ cp = jc.getConstantPool();
+ (new DescendingVisitor(jc, this)).visit();
+ }
+ /**
+ * Returns if the JavaClass this InnerClassDetector is working on
+ * has an Inner Class reference in its constant pool.
+ */
+ public boolean innerClassReferenced(){
+ return hasInnerClass;
+ }
+ /** This method casually visits ConstantClass references. */
+ public void visitConstantClass(ConstantClass obj){
+ Constant c = cp.getConstant(obj.getNameIndex());
+ if (c instanceof ConstantUtf8){ //Ignore the case where it's not a ConstantUtf8 here, we'll find out later.
+ String classname = ((ConstantUtf8) c).getBytes();
+ if (classname.startsWith(jc.getClassName().replace('.','/')+"$")){
+ hasInnerClass = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * This method is here to save typing work and improve code readability.
+ */
+ private static String tostring(Node n){
+ return new StringRepresentation(n).toString();
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/statics/Pass3aVerifier.java b/src/java/org/apache/bcel/verifier/statics/Pass3aVerifier.java
new file mode 100644
index 00000000..109006d6
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/statics/Pass3aVerifier.java
@@ -0,0 +1,1070 @@
+package org.apache.bcel.verifier.statics;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.*;
+import org.apache.bcel.generic.*;
+import org.apache.bcel.classfile.*;
+import org.apache.bcel.verifier.*;
+import org.apache.bcel.verifier.exc.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * This PassVerifier verifies a class file according to
+ * pass 3, static part as described in The Java Virtual
+ * Machine Specification, 2nd edition.
+ * More detailed information is to be found at the do_verify()
+ * method's documentation.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ * @see #do_verify()
+ */
+public final class Pass3aVerifier extends PassVerifier{
+
+ /** The Verifier that created this. */
+ private Verifier myOwner;
+
+ /**
+ * The method number to verify.
+ * This is the index in the array returned
+ * by JavaClass.getMethods().
+ */
+ private int method_no;
+
+ /** The one and only InstructionList object used by an instance of this class. It's here for performance reasons by do_verify() and its callees. */
+ InstructionList instructionList;
+ /** The one and only Code object used by an instance of this class. It's here for performance reasons by do_verify() and its callees. */
+ Code code;
+
+ /** Should only be instantiated by a Verifier. */
+ public Pass3aVerifier(Verifier owner, int method_no){
+ myOwner = owner;
+ this.method_no = method_no;
+ }
+
+ /**
+ * Pass 3a is the verification of static constraints of
+ * JVM code (such as legal targets of branch instructions).
+ * This is the part of pass 3 where you do not need data
+ * flow analysis.
+ * JustIce also delays the checks for a correct exception
+ * table of a Code attribute and correct line number entries
+ * in a LineNumberTable attribute of a Code attribute (which
+ * conceptually belong to pass 2) to this pass. Also, most
+ * of the check for valid local variable entries in a
+ * LocalVariableTable attribute of a Code attribute is
+ * delayed until this pass.
+ * All these checks need access to the code array of the
+ * Code attribute.
+ *
+ * @throws InvalidMethodException if the method to verify does not exist.
+ */
+ public VerificationResult do_verify(){
+ if (myOwner.doPass2().equals(VerificationResult.VR_OK)){
+ // Okay, class file was loaded correctly by Pass 1
+ // and satisfies static constraints of Pass 2.
+ JavaClass jc = Repository.lookupClass(myOwner.getClassName());
+ Method[] methods = jc.getMethods();
+ if (method_no >= methods.length){
+ throw new InvalidMethodException("METHOD DOES NOT EXIST!");
+ }
+ Method method = methods[method_no];
+ code = method.getCode();
+
+ // No Code? Nothing to verify!
+ if ( method.isAbstract() || method.isNative() ){ // IF mg HAS NO CODE (static constraint of Pass 2)
+ return VerificationResult.VR_OK;
+ }
+
+ // TODO:
+ // We want a very sophisticated code examination here with good explanations
+ // on where to look for an illegal instruction or such.
+ // Only after that we should try to build an InstructionList and throw an
+ // AssertionViolatedException if after our examination InstructionList building
+ // still fails.
+ // That examination should be implemented in a byte-oriented way, i.e. look for
+ // an instruction, make sure its validity, count its length, find the next
+ // instruction and so on.
+ try{
+ instructionList = new InstructionList(method.getCode().getCode());
+ }
+ catch(RuntimeException re){
+ return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Bad bytecode in the code array of the Code attribute of method '"+method+"'.");
+ }
+
+ instructionList.setPositions(true);
+
+ // Start verification.
+ VerificationResult vr = VerificationResult.VR_OK; //default
+ try{
+ delayedPass2Checks();
+ }
+ catch(ClassConstraintException cce){
+ vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, cce.getMessage());
+ return vr;
+ }
+ try{
+ pass3StaticInstructionChecks();
+ pass3StaticInstructionOperandsChecks();
+ }
+ catch(StaticCodeConstraintException scce){
+ vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, scce.getMessage());
+ }
+ return vr;
+ }
+ else{ //did not pass Pass 2.
+ return VerificationResult.VR_NOTYET;
+ }
+ }
+
+ /**
+ * These are the checks that could be done in pass 2 but are delayed to pass 3
+ * for performance reasons. Also, these checks need access to the code array
+ * of the Code attribute of a Method so it's okay to perform them here.
+ * Also see the description of the do_verify() method.
+ *
+ * @throws ClassConstraintException if the verification fails.
+ * @see #do_verify()
+ */
+ private void delayedPass2Checks(){
+
+ int[] instructionPositions = instructionList.getInstructionPositions();
+ int codeLength = code.getCode().length;
+
+ /////////////////////
+ // LineNumberTable //
+ /////////////////////
+ LineNumberTable lnt = code.getLineNumberTable();
+ if (lnt != null){
+ LineNumber[] lineNumbers = lnt.getLineNumberTable();
+ IntList offsets = new IntList();
+ lineNumber_loop: for (int i=0; i < lineNumbers.length; i++){ // may appear in any order.
+ for (int j=0; j < instructionPositions.length; j++){
+ // TODO: Make this a binary search! The instructionPositions array is naturally ordered!
+ int offset = lineNumbers[i].getStartPC();
+ if (instructionPositions[j] == offset){
+ if (offsets.contains(offset)){
+ addMessage("LineNumberTable attribute '"+code.getLineNumberTable()+"' refers to the same code offset ('"+offset+"') more than once which is violating the semantics [but is sometimes produced by IBM's 'jikes' compiler].");
+ }
+ else{
+ offsets.add(offset);
+ }
+ continue lineNumber_loop;
+ }
+ }
+ throw new ClassConstraintException("Code attribute '"+code+"' has a LineNumberTable attribute '"+code.getLineNumberTable()+"' referring to a code offset ('"+lineNumbers[i].getStartPC()+"') that does not exist.");
+ }
+ }
+
+ ///////////////////////////
+ // LocalVariableTable(s) //
+ ///////////////////////////
+ /* We cannot use code.getLocalVariableTable() because there could be more
+ than only one. This is a bug in BCEL. */
+ Attribute[] atts = code.getAttributes();
+ for (int a=0; a<atts.length; a++){
+ if (atts[a] instanceof LocalVariableTable){
+ LocalVariableTable lvt = (LocalVariableTable) atts[a];
+ if (lvt != null){
+ LocalVariable[] localVariables = lvt.getLocalVariableTable();
+ for (int i=0; i<localVariables.length; i++){
+ int startpc = localVariables[i].getStartPC();
+ int length = localVariables[i].getLength();
+
+ if (!contains(instructionPositions, startpc)){
+ throw new ClassConstraintException("Code attribute '"+code+"' has a LocalVariableTable attribute '"+code.getLocalVariableTable()+"' referring to a code offset ('"+startpc+"') that does not exist.");
+ }
+ if ( (!contains(instructionPositions, startpc+length)) && (startpc+length != codeLength) ){
+ throw new ClassConstraintException("Code attribute '"+code+"' has a LocalVariableTable attribute '"+code.getLocalVariableTable()+"' referring to a code offset start_pc+length ('"+(startpc+length)+"') that does not exist.");
+ }
+ }
+ }
+ }
+ }
+
+ ////////////////////
+ // ExceptionTable //
+ ////////////////////
+ // In BCEL's "classfile" API, the startPC/endPC-notation is
+ // inclusive/exclusive as in the Java Virtual Machine Specification.
+ // WARNING: This is not true for BCEL's "generic" API.
+ CodeException[] exceptionTable = code.getExceptionTable();
+ for (int i=0; i<exceptionTable.length; i++){
+ int startpc = exceptionTable[i].getStartPC();
+ int endpc = exceptionTable[i].getEndPC();
+ int handlerpc = exceptionTable[i].getHandlerPC();
+ if (startpc >= endpc){
+ throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has its start_pc ('"+startpc+"') not smaller than its end_pc ('"+endpc+"').");
+ }
+ if (!contains(instructionPositions, startpc)){
+ throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its start_pc ('"+startpc+"').");
+ }
+ if ( (!contains(instructionPositions, endpc)) && (endpc != codeLength)){
+ throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its end_pc ('"+startpc+"') [that is also not equal to code_length ('"+codeLength+"')].");
+ }
+ if (!contains(instructionPositions, handlerpc)){
+ throw new ClassConstraintException("Code attribute '"+code+"' has an exception_table entry '"+exceptionTable[i]+"' that has a non-existant bytecode offset as its handler_pc ('"+handlerpc+"').");
+ }
+ }
+ }
+
+ /**
+ * These are the checks if constraints are satisfied which are described in the
+ * Java Virtual Machine Specification, Second Edition as Static Constraints on
+ * the instructions of Java Virtual Machine Code (chapter 4.8.1).
+ *
+ * @throws StaticCodeConstraintException if the verification fails.
+ */
+ private void pass3StaticInstructionChecks(){
+
+ // Code array must not be empty:
+ // Enforced in pass 2 (also stated in the static constraints of the Code
+ // array in vmspec2), together with pass 1 (reading code_length bytes and
+ // interpreting them as code[]). So this must not be checked again here.
+
+ if (! (code.getCode().length < 65536)){// contradicts vmspec2 page 152 ("Limitations"), but is on page 134.
+ throw new StaticCodeInstructionConstraintException("Code array in code attribute '"+code+"' too big: must be smaller than 65536 bytes.");
+ }
+
+ // First opcode at offset 0: okay, that's clear. Nothing to do.
+
+ // Only instances of the instructions documented in Section 6.4 may appear in
+ // the code array.
+
+ // For BCEL's sake, we cannot handle WIDE stuff, but hopefully BCEL does its job right :)
+
+ // The last byte of the last instruction in the code array must be the byte at index
+ // code_length-1 : See the do_verify() comments. We actually don't iterate through the
+ // byte array, but use an InstructionList so we cannot check for this. But BCEL does
+ // things right, so it's implicitely okay.
+
+ // TODO: Check how BCEL handles (and will handle) instructions like IMPDEP1, IMPDEP2,
+ // BREAKPOINT... that BCEL knows about but which are illegal anyway.
+ // We currently go the safe way here.
+ InstructionHandle ih = instructionList.getStart();
+ while (ih != null){
+ Instruction i = ih.getInstruction();
+ if (i instanceof IMPDEP1){
+ throw new StaticCodeInstructionConstraintException("IMPDEP1 must not be in the code, it is an illegal instruction for _internal_ JVM use!");
+ }
+ if (i instanceof IMPDEP2){
+ throw new StaticCodeInstructionConstraintException("IMPDEP2 must not be in the code, it is an illegal instruction for _internal_ JVM use!");
+ }
+ if (i instanceof BREAKPOINT){
+ throw new StaticCodeInstructionConstraintException("BREAKPOINT must not be in the code, it is an illegal instruction for _internal_ JVM use!");
+ }
+ ih = ih.getNext();
+ }
+
+ // The original verifier seems to do this check here, too.
+ // An unreachable last instruction may also not fall through the
+ // end of the code, which is stupid -- but with the original
+ // verifier's subroutine semantics one cannot predict reachability.
+ Instruction last = instructionList.getEnd().getInstruction();
+ if (! ((last instanceof ReturnInstruction) ||
+ (last instanceof RET) ||
+ (last instanceof GotoInstruction) ||
+ (last instanceof ATHROW) )) // JSR / JSR_W would possibly RETurn and then fall off the code!
+ throw new StaticCodeInstructionConstraintException("Execution must not fall off the bottom of the code array. This constraint is enforced statically as some existing verifiers do - so it may be a false alarm if the last instruction is not reachable.");
+ }
+
+ /**
+ * These are the checks for the satisfaction of constraints which are described in the
+ * Java Virtual Machine Specification, Second Edition as Static Constraints on
+ * the operands of instructions of Java Virtual Machine Code (chapter 4.8.1).
+ * BCEL parses the code array to create an InstructionList and therefore has to check
+ * some of these constraints. Additional checks are also implemented here.
+ *
+ * @throws StaticCodeConstraintException if the verification fails.
+ */
+ private void pass3StaticInstructionOperandsChecks(){
+ // When building up the InstructionList, BCEL has already done all those checks
+ // mentioned in The Java Virtual Machine Specification, Second Edition, as
+ // "static constraints on the operands of instructions in the code array".
+ // TODO: see the do_verify() comments. Maybe we should really work on the
+ // byte array first to give more comprehensive messages.
+ // TODO: Review Exception API, possibly build in some "offending instruction" thing
+ // when we're ready to insulate the offending instruction by doing the
+ // above thing.
+
+ // TODO: Implement as much as possible here. BCEL does _not_ check everything.
+
+ ConstantPoolGen cpg = new ConstantPoolGen(Repository.lookupClass(myOwner.getClassName()).getConstantPool());
+ InstOperandConstraintVisitor v = new InstOperandConstraintVisitor(cpg);
+
+ // Checks for the things BCEL does _not_ handle itself.
+ InstructionHandle ih = instructionList.getStart();
+ while (ih != null){
+ Instruction i = ih.getInstruction();
+
+ // An "own" constraint, due to JustIce's new definition of what "subroutine" means.
+ if (i instanceof JsrInstruction){
+ InstructionHandle target = ((JsrInstruction) i).getTarget();
+ if (target == instructionList.getStart()){
+ throw new StaticCodeInstructionOperandConstraintException("Due to JustIce's clear definition of subroutines, no JSR or JSR_W may have a top-level instruction (such as the very first instruction, which is targeted by instruction '"+ih+"' as its target.");
+ }
+ if (!(target.getInstruction() instanceof ASTORE)){
+ throw new StaticCodeInstructionOperandConstraintException("Due to JustIce's clear definition of subroutines, no JSR or JSR_W may target anything else than an ASTORE instruction. Instruction '"+ih+"' targets '"+target+"'.");
+ }
+ }
+
+ // vmspec2, page 134-137
+ ih.accept(v);
+
+ ih = ih.getNext();
+ }
+
+ }
+
+ /** A small utility method returning if a given int i is in the given int[] ints. */
+ private static boolean contains(int[] ints, int i){
+ for (int j=0; j<ints.length; j++){
+ if (ints[j]==i) return true;
+ }
+ return false;
+ }
+
+ /** Returns the method number as supplied when instantiating. */
+ public int getMethodNo(){
+ return method_no;
+ }
+
+ /**
+ * This visitor class does the actual checking for the instruction
+ * operand's constraints.
+ */
+ private class InstOperandConstraintVisitor extends org.apache.bcel.generic.EmptyVisitor{
+ /** The ConstantPoolGen instance this Visitor operates on. */
+ private ConstantPoolGen cpg;
+
+ /** The only Constructor. */
+ InstOperandConstraintVisitor(ConstantPoolGen cpg){
+ this.cpg = cpg;
+ }
+
+ /**
+ * Utility method to return the max_locals value of the method verified
+ * by the surrounding Pass3aVerifier instance.
+ */
+ private int max_locals(){
+ return Repository.lookupClass(myOwner.getClassName()).getMethods()[method_no].getCode().getMaxLocals();
+ }
+
+ /**
+ * A utility method to always raise an exeption.
+ */
+ private void constraintViolated(Instruction i, String message) {
+ throw new StaticCodeInstructionOperandConstraintException("Instruction "+i+" constraint violated: "+message);
+ }
+
+ /**
+ * A utility method to raise an exception if the index is not
+ * a valid constant pool index.
+ */
+ private void indexValid(Instruction i, int idx){
+ if (idx < 0 || idx >= cpg.getSize()){
+ constraintViolated(i, "Illegal constant pool index '"+idx+"'.");
+ }
+ }
+
+ ///////////////////////////////////////////////////////////
+ // The Java Virtual Machine Specification, pages 134-137 //
+ ///////////////////////////////////////////////////////////
+ /**
+ * Assures the generic preconditions of a LoadClass instance.
+ * The referenced class is loaded and pass2-verified.
+ */
+ public void visitLoadClass(LoadClass o){
+ ObjectType t = o.getLoadClassType(cpg);
+ if (t != null){// null means "no class is loaded"
+ Verifier v = VerifierFactory.getVerifier(t.getClassName());
+ VerificationResult vr = v.doPass1();
+ if (vr.getStatus() != VerificationResult.VERIFIED_OK){
+ constraintViolated((Instruction) o, "Class '"+o.getLoadClassType(cpg).getClassName()+"' is referenced, but cannot be loaded: '"+vr+"'.");
+ }
+ }
+ }
+
+ // The target of each jump and branch instruction [...] must be the opcode [...]
+ // BCEL _DOES_ handle this.
+
+ // tableswitch: BCEL will do it, supposedly.
+
+ // lookupswitch: BCEL will do it, supposedly.
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ // LDC and LDC_W (LDC_W is a subclass of LDC in BCEL's model)
+ public void visitLDC(LDC o){
+ indexValid(o, o.getIndex());
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! ( (c instanceof ConstantInteger) ||
+ (c instanceof ConstantFloat) ||
+ (c instanceof ConstantString) ) ){
+ constraintViolated(o, "Operand of LDC or LDC_W must be one of CONSTANT_Integer, CONSTANT_Float or CONSTANT_String, but is '"+c+"'.");
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ // LDC2_W
+ public void visitLDC2_W(LDC2_W o){
+ indexValid(o, o.getIndex());
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! ( (c instanceof ConstantLong) ||
+ (c instanceof ConstantDouble) ) ){
+ constraintViolated(o, "Operand of LDC2_W must be CONSTANT_Long or CONSTANT_Double, but is '"+c+"'.");
+ }
+ try{
+ indexValid(o, o.getIndex()+1);
+ }
+ catch(StaticCodeInstructionOperandConstraintException e){
+ throw new AssertionViolatedException("OOPS: Does not BCEL handle that? LDC2_W operand has a problem.");
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ //getfield, putfield, getstatic, putstatic
+ public void visitFieldInstruction(FieldInstruction o){
+ indexValid(o, o.getIndex());
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! (c instanceof ConstantFieldref)){
+ constraintViolated(o, "Indexing a constant that's not a CONSTANT_Fieldref but a '"+c+"'.");
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitInvokeInstruction(InvokeInstruction o){
+ indexValid(o, o.getIndex());
+ if ( (o instanceof INVOKEVIRTUAL) ||
+ (o instanceof INVOKESPECIAL) ||
+ (o instanceof INVOKESTATIC) ){
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! (c instanceof ConstantMethodref)){
+ constraintViolated(o, "Indexing a constant that's not a CONSTANT_Methodref but a '"+c+"'.");
+ }
+ else{
+ // Constants are okay due to pass2.
+ ConstantNameAndType cnat = (ConstantNameAndType) (cpg.getConstant(((ConstantMethodref) c).getNameAndTypeIndex()));
+ ConstantUtf8 cutf8 = (ConstantUtf8) (cpg.getConstant(cnat.getNameIndex()));
+ if (cutf8.getBytes().equals(Constants.CONSTRUCTOR_NAME) && (!(o instanceof INVOKESPECIAL)) ){
+ constraintViolated(o, "Only INVOKESPECIAL is allowed to invoke instance initialization methods.");
+ }
+ if ( (! (cutf8.getBytes().equals(Constants.CONSTRUCTOR_NAME)) ) && (cutf8.getBytes().startsWith("<")) ){
+ constraintViolated(o, "No method with a name beginning with '<' other than the instance initialization methods may be called by the method invocation instructions.");
+ }
+ }
+ }
+ else{ //if (o instanceof INVOKEINTERFACE){
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! (c instanceof ConstantInterfaceMethodref)){
+ constraintViolated(o, "Indexing a constant that's not a CONSTANT_InterfaceMethodref but a '"+c+"'.");
+ }
+ // TODO: From time to time check if BCEL allows to detect if the
+ // 'count' operand is consistent with the information in the
+ // CONSTANT_InterfaceMethodref and if the last operand is zero.
+ // By now, BCEL hides those two operands because they're superfluous.
+
+ // Invoked method must not be <init> or <clinit>
+ ConstantNameAndType cnat = (ConstantNameAndType) (cpg.getConstant(((ConstantInterfaceMethodref)c).getNameAndTypeIndex()));
+ String name = ((ConstantUtf8) (cpg.getConstant(cnat.getNameIndex()))).getBytes();
+ if (name.equals(Constants.CONSTRUCTOR_NAME)){
+ constraintViolated(o, "Method to invoke must not be '"+Constants.CONSTRUCTOR_NAME+"'.");
+ }
+ if (name.equals(Constants.STATIC_INITIALIZER_NAME)){
+ constraintViolated(o, "Method to invoke must not be '"+Constants.STATIC_INITIALIZER_NAME+"'.");
+ }
+ }
+
+ // The LoadClassType is the method-declaring class, so we have to check the other types.
+
+ Type t = o.getReturnType(cpg);
+ if (t instanceof ArrayType){
+ t = ((ArrayType) t).getBasicType();
+ }
+ if (t instanceof ObjectType){
+ Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName());
+ VerificationResult vr = v.doPass2();
+ if (vr.getStatus() != VerificationResult.VERIFIED_OK){
+ constraintViolated(o, "Return type class/interface could not be verified successfully: '"+vr.getMessage()+"'.");
+ }
+ }
+
+ Type[] ts = o.getArgumentTypes(cpg);
+ for (int i=0; i<ts.length; i++){
+ t = ts[i];
+ if (t instanceof ArrayType){
+ t = ((ArrayType) t).getBasicType();
+ }
+ if (t instanceof ObjectType){
+ Verifier v = VerifierFactory.getVerifier(((ObjectType) t).getClassName());
+ VerificationResult vr = v.doPass2();
+ if (vr.getStatus() != VerificationResult.VERIFIED_OK){
+ constraintViolated(o, "Argument type class/interface could not be verified successfully: '"+vr.getMessage()+"'.");
+ }
+ }
+ }
+
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitINSTANCEOF(INSTANCEOF o){
+ indexValid(o, o.getIndex());
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! (c instanceof ConstantClass)){
+ constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitCHECKCAST(CHECKCAST o){
+ indexValid(o, o.getIndex());
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! (c instanceof ConstantClass)){
+ constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitNEW(NEW o){
+ indexValid(o, o.getIndex());
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! (c instanceof ConstantClass)){
+ constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
+ }
+ else{
+ ConstantUtf8 cutf8 = (ConstantUtf8) (cpg.getConstant( ((ConstantClass) c).getNameIndex() ));
+ Type t = Type.getType("L"+cutf8.getBytes()+";");
+ if (t instanceof ArrayType){
+ constraintViolated(o, "NEW must not be used to create an array.");
+ }
+ }
+
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitMULTIANEWARRAY(MULTIANEWARRAY o){
+ indexValid(o, o.getIndex());
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! (c instanceof ConstantClass)){
+ constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
+ }
+ int dimensions2create = o.getDimensions();
+ if (dimensions2create < 1){
+ constraintViolated(o, "Number of dimensions to create must be greater than zero.");
+ }
+ Type t = o.getType(cpg);
+ if (t instanceof ArrayType){
+ int dimensions = ((ArrayType) t).getDimensions();
+ if (dimensions < dimensions2create){
+ constraintViolated(o, "Not allowed to create array with more dimensions ('+dimensions2create+') than the one referenced by the CONSTANT_Class '"+t+"'.");
+ }
+ }
+ else{
+ constraintViolated(o, "Expecting a CONSTANT_Class referencing an array type. [Constraint not found in The Java Virtual Machine Specification, Second Edition, 4.8.1]");
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitANEWARRAY(ANEWARRAY o){
+ indexValid(o, o.getIndex());
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! (c instanceof ConstantClass)){
+ constraintViolated(o, "Expecting a CONSTANT_Class operand, but found a '"+c+"'.");
+ }
+ Type t = o.getType(cpg);
+ if (t instanceof ArrayType){
+ int dimensions = ((ArrayType) t).getDimensions();
+ if (dimensions >= 255){
+ constraintViolated(o, "Not allowed to create an array with more than 255 dimensions.");
+ }
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitNEWARRAY(NEWARRAY o){
+ byte t = o.getTypecode();
+ if (! ( (t == Constants.T_BOOLEAN) ||
+ (t == Constants.T_CHAR) ||
+ (t == Constants.T_FLOAT) ||
+ (t == Constants.T_DOUBLE) ||
+ (t == Constants.T_BYTE) ||
+ (t == Constants.T_SHORT) ||
+ (t == Constants.T_INT) ||
+ (t == Constants.T_LONG) ) ){
+ constraintViolated(o, "Illegal type code '+t+' for 'atype' operand.");
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitILOAD(ILOAD o){
+ int idx = o.getIndex();
+ if (idx < 0){
+ constraintViolated(o, "Index '"+idx+"' must be non-negative.");
+ }
+ else{
+ int maxminus1 = max_locals()-1;
+ if (idx > maxminus1){
+ constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
+ }
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitFLOAD(FLOAD o){
+ int idx = o.getIndex();
+ if (idx < 0){
+ constraintViolated(o, "Index '"+idx+"' must be non-negative.");
+ }
+ else{
+ int maxminus1 = max_locals()-1;
+ if (idx > maxminus1){
+ constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
+ }
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitALOAD(ALOAD o){
+ int idx = o.getIndex();
+ if (idx < 0){
+ constraintViolated(o, "Index '"+idx+"' must be non-negative.");
+ }
+ else{
+ int maxminus1 = max_locals()-1;
+ if (idx > maxminus1){
+ constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
+ }
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitISTORE(ISTORE o){
+ int idx = o.getIndex();
+ if (idx < 0){
+ constraintViolated(o, "Index '"+idx+"' must be non-negative.");
+ }
+ else{
+ int maxminus1 = max_locals()-1;
+ if (idx > maxminus1){
+ constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
+ }
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitFSTORE(FSTORE o){
+ int idx = o.getIndex();
+ if (idx < 0){
+ constraintViolated(o, "Index '"+idx+"' must be non-negative.");
+ }
+ else{
+ int maxminus1 = max_locals()-1;
+ if (idx > maxminus1){
+ constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
+ }
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitASTORE(ASTORE o){
+ int idx = o.getIndex();
+ if (idx < 0){
+ constraintViolated(o, "Index '"+idx+"' must be non-negative.");
+ }
+ else{
+ int maxminus1 = max_locals()-1;
+ if (idx > maxminus1){
+ constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
+ }
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitIINC(IINC o){
+ int idx = o.getIndex();
+ if (idx < 0){
+ constraintViolated(o, "Index '"+idx+"' must be non-negative.");
+ }
+ else{
+ int maxminus1 = max_locals()-1;
+ if (idx > maxminus1){
+ constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
+ }
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitRET(RET o){
+ int idx = o.getIndex();
+ if (idx < 0){
+ constraintViolated(o, "Index '"+idx+"' must be non-negative.");
+ }
+ else{
+ int maxminus1 = max_locals()-1;
+ if (idx > maxminus1){
+ constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-1 '"+maxminus1+"'.");
+ }
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitLLOAD(LLOAD o){
+ int idx = o.getIndex();
+ if (idx < 0){
+ constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
+ }
+ else{
+ int maxminus2 = max_locals()-2;
+ if (idx > maxminus2){
+ constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
+ }
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitDLOAD(DLOAD o){
+ int idx = o.getIndex();
+ if (idx < 0){
+ constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
+ }
+ else{
+ int maxminus2 = max_locals()-2;
+ if (idx > maxminus2){
+ constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
+ }
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitLSTORE(LSTORE o){
+ int idx = o.getIndex();
+ if (idx < 0){
+ constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
+ }
+ else{
+ int maxminus2 = max_locals()-2;
+ if (idx > maxminus2){
+ constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
+ }
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitDSTORE(DSTORE o){
+ int idx = o.getIndex();
+ if (idx < 0){
+ constraintViolated(o, "Index '"+idx+"' must be non-negative. [Constraint by JustIce as an analogon to the single-slot xLOAD/xSTORE instructions; may not happen anyway.]");
+ }
+ else{
+ int maxminus2 = max_locals()-2;
+ if (idx > maxminus2){
+ constraintViolated(o, "Index '"+idx+"' must not be greater than max_locals-2 '"+maxminus2+"'.");
+ }
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitLOOKUPSWITCH(LOOKUPSWITCH o){
+ int[] matchs = o.getMatchs();
+ int max = Integer.MIN_VALUE;
+ for (int i=0; i<matchs.length; i++){
+ if (matchs[i] == max && i != 0){
+ constraintViolated(o, "Match '"+matchs[i]+"' occurs more than once.");
+ }
+ if (matchs[i] < max){
+ constraintViolated(o, "Lookup table must be sorted but isn't.");
+ }
+ else{
+ max = matchs[i];
+ }
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitTABLESWITCH(TABLESWITCH o){
+ // "high" must be >= "low". We cannot check this, as BCEL hides
+ // it from us.
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitPUTSTATIC(PUTSTATIC o){
+ String field_name = o.getFieldName(cpg);
+ JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
+ Field[] fields = jc.getFields();
+ Field f = null;
+ for (int i=0; i<fields.length; i++){
+ if (fields[i].getName().equals(field_name)){
+ f = fields[i];
+ break;
+ }
+ }
+ if (f == null){
+ throw new AssertionViolatedException("Field not found?!?");
+ }
+
+ if (f.isFinal()){
+ if (!(myOwner.getClassName().equals(o.getClassType(cpg).getClassName()))){
+ constraintViolated(o, "Referenced field '"+f+"' is final and must therefore be declared in the current class '"+myOwner.getClassName()+"' which is not the case: it is declared in '"+o.getClassType(cpg).getClassName()+"'.");
+ }
+ }
+
+ if (! (f.isStatic())){
+ constraintViolated(o, "Referenced field '"+f+"' is not static which it should be.");
+ }
+
+ String meth_name = Repository.lookupClass(myOwner.getClassName()).getMethods()[method_no].getName();
+
+ // If it's an interface, it can be set only in <clinit>.
+ if ((!(jc.isClass())) && (!(meth_name.equals(Constants.STATIC_INITIALIZER_NAME)))){
+ constraintViolated(o, "Interface field '"+f+"' must be set in a '"+Constants.STATIC_INITIALIZER_NAME+"' method.");
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitGETSTATIC(GETSTATIC o){
+ String field_name = o.getFieldName(cpg);
+ JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
+ Field[] fields = jc.getFields();
+ Field f = null;
+ for (int i=0; i<fields.length; i++){
+ if (fields[i].getName().equals(field_name)){
+ f = fields[i];
+ break;
+ }
+ }
+ if (f == null){
+ throw new AssertionViolatedException("Field not found?!?");
+ }
+
+ if (! (f.isStatic())){
+ constraintViolated(o, "Referenced field '"+f+"' is not static which it should be.");
+ }
+ }
+
+ /* Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ //public void visitPUTFIELD(PUTFIELD o){
+ // for performance reasons done in Pass 3b
+ //}
+
+ /* Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ //public void visitGETFIELD(GETFIELD o){
+ // for performance reasons done in Pass 3b
+ //}
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitINVOKEINTERFACE(INVOKEINTERFACE o){
+ // INVOKEINTERFACE is a LoadClass; the Class where the referenced method is declared in,
+ // is therefore resolved/verified.
+ // INVOKEINTERFACE is an InvokeInstruction, the argument and return types are resolved/verified,
+ // too. So are the allowed method names.
+ String classname = o.getClassName(cpg);
+ JavaClass jc = Repository.lookupClass(classname);
+ Method[] ms = jc.getMethods();
+ Method m = null;
+ for (int i=0; i<ms.length; i++){
+ if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
+ (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
+ (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
+ m = ms[i];
+ break;
+ }
+ }
+ if (m == null){
+ constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature not found in class '"+jc.getClassName()+"'. The native verfier does allow the method to be declared in some superinterface, which the Java Virtual Machine Specification, Second Edition does not.");
+ }
+ if (jc.isClass()){
+ constraintViolated(o, "Referenced class '"+jc.getClassName()+"' is a class, but not an interface as expected.");
+ }
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitINVOKESPECIAL(INVOKESPECIAL o){
+ // INVOKESPECIAL is a LoadClass; the Class where the referenced method is declared in,
+ // is therefore resolved/verified.
+ // INVOKESPECIAL is an InvokeInstruction, the argument and return types are resolved/verified,
+ // too. So are the allowed method names.
+ String classname = o.getClassName(cpg);
+ JavaClass jc = Repository.lookupClass(classname);
+ Method[] ms = jc.getMethods();
+ Method m = null;
+ for (int i=0; i<ms.length; i++){
+ if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
+ (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
+ (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
+ m = ms[i];
+ break;
+ }
+ }
+ if (m == null){
+ constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature not found in class '"+jc.getClassName()+"'. The native verfier does allow the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not.");
+ }
+
+ JavaClass current = Repository.lookupClass(myOwner.getClassName());
+ if (current.isSuper()){
+
+ if ((Repository.instanceOf( current, jc )) && (!current.equals(jc))){
+
+ if (! (o.getMethodName(cpg).equals(Constants.CONSTRUCTOR_NAME) )){
+ // Special lookup procedure for ACC_SUPER classes.
+
+ int supidx = -1;
+
+ Method meth = null;
+ while (supidx != 0){
+ supidx = current.getSuperclassNameIndex();
+ current = Repository.lookupClass(current.getSuperclassName());
+
+ Method[] meths = current.getMethods();
+ for (int i=0; i<meths.length; i++){
+ if ( (meths[i].getName().equals(o.getMethodName(cpg))) &&
+ (Type.getReturnType(meths[i].getSignature()).equals(o.getReturnType(cpg))) &&
+ (objarrayequals(Type.getArgumentTypes(meths[i].getSignature()), o.getArgumentTypes(cpg))) ){
+ meth = meths[i];
+ break;
+ }
+ }
+ if (meth != null) break;
+ }
+ if (meth == null){
+ constraintViolated(o, "ACC_SUPER special lookup procedure not successful: method '"+o.getMethodName(cpg)+"' with proper signature not declared in superclass hierarchy.");
+ }
+ }
+ }
+ }
+
+
+ }
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitINVOKESTATIC(INVOKESTATIC o){
+ // INVOKESTATIC is a LoadClass; the Class where the referenced method is declared in,
+ // is therefore resolved/verified.
+ // INVOKESTATIC is an InvokeInstruction, the argument and return types are resolved/verified,
+ // too. So are the allowed method names.
+ String classname = o.getClassName(cpg);
+ JavaClass jc = Repository.lookupClass(classname);
+ Method[] ms = jc.getMethods();
+ Method m = null;
+ for (int i=0; i<ms.length; i++){
+ if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
+ (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
+ (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
+ m = ms[i];
+ break;
+ }
+ }
+ if (m == null){
+ constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature not found in class '"+jc.getClassName()+"'. The native verifier possibly allows the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not.");
+ }
+
+ if (! (m.isStatic())){ // implies it's not abstract, verified in pass 2.
+ constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' has ACC_STATIC unset.");
+ }
+
+ }
+
+
+ /** Checks if the constraints of operands of the said instruction(s) are satisfied. */
+ public void visitINVOKEVIRTUAL(INVOKEVIRTUAL o){
+ // INVOKEVIRTUAL is a LoadClass; the Class where the referenced method is declared in,
+ // is therefore resolved/verified.
+ // INVOKEVIRTUAL is an InvokeInstruction, the argument and return types are resolved/verified,
+ // too. So are the allowed method names.
+ String classname = o.getClassName(cpg);
+ JavaClass jc = Repository.lookupClass(classname);
+ Method[] ms = jc.getMethods();
+ Method m = null;
+ for (int i=0; i<ms.length; i++){
+ if ( (ms[i].getName().equals(o.getMethodName(cpg))) &&
+ (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) &&
+ (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){
+ m = ms[i];
+ break;
+ }
+ }
+ if (m == null){
+ constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature not found in class '"+jc.getClassName()+"'. The native verfier does allow the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not.");
+ }
+ if (! (jc.isClass())){
+ constraintViolated(o, "Referenced class '"+jc.getClassName()+"' is an interface, but not a class as expected.");
+ }
+
+ }
+
+
+ // WIDE stuff is BCEL-internal and cannot be checked here.
+
+ /**
+ * A utility method like equals(Object) for arrays.
+ * The equality of the elements is based on their equals(Object)
+ * method instead of their object identity.
+ */
+ private boolean objarrayequals(Object[] o, Object[] p){
+ if (o.length != p.length){
+ return false;
+ }
+
+ for (int i=0; i<o.length; i++){
+ if (! (o[i].equals(p[i])) ){
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/statics/StringRepresentation.java b/src/java/org/apache/bcel/verifier/statics/StringRepresentation.java
new file mode 100644
index 00000000..93f36373
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/statics/StringRepresentation.java
@@ -0,0 +1,202 @@
+package org.apache.bcel.verifier.statics;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.classfile.*;
+
+/**
+ * BCEL's Node classes (those from the classfile API that <B>accept()</B> Visitor
+ * instances) have <B>toString()</B> methods that were not designed to be robust,
+ * this gap is closed by this class.
+ * When performing class file verification, it may be useful to output which
+ * entity (e.g. a <B>Code</B> instance) is not satisfying the verifier's
+ * constraints, but in this case it could be possible for the <B>toString()</B>
+ * method to throw a RuntimeException.
+ * A (new StringRepresentation(Node n)).toString() never throws any exception.
+ * Note that this class also serves as a placeholder for more sophisticated message
+ * handling in future versions of JustIce.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class StringRepresentation extends org.apache.bcel.classfile.EmptyVisitor implements Visitor{
+ /** The string representation, created by a visitXXX() method, output by toString(). */
+ private String tostring;
+ /**
+ * Creates a new StringRepresentation object which is the representation of n.
+ *
+ * @see #toString()
+ */
+ public StringRepresentation(Node n){
+ n.accept(this);
+ }
+ /**
+ * Returns the String representation.
+ */
+ public String toString(){
+ return tostring;
+ }
+ /**
+ * Returns the String representation of the Node object obj;
+ * this is obj.toString() if it does not throw any RuntimeException,
+ * or else it is a string derived only from obj's class name.
+ */
+ private String toString(Node obj){
+ String ret;
+ try{
+ ret = obj.toString();
+ }
+ catch(RuntimeException e){
+ String s = obj.getClass().getName();
+ s = s.substring(s.lastIndexOf(".")+1);
+ ret = "<<"+s+">>";
+ }
+ return ret;
+ }
+ ////////////////////////////////
+ // Visitor methods start here //
+ ////////////////////////////////
+ // We don't of course need to call some default implementation:
+ // e.g. we could also simply output "Code" instead of a possibly
+ // lengthy Code attribute's toString().
+ public void visitCode(Code obj){
+ //tostring = toString(obj);
+ tostring = "<CODE>"; // We don't need real code outputs.
+ }
+ public void visitCodeException(CodeException obj){
+ tostring = toString(obj);
+ }
+ public void visitConstantClass(ConstantClass obj){
+ tostring = toString(obj);
+ }
+ public void visitConstantDouble(ConstantDouble obj){
+ tostring = toString(obj);
+ }
+ public void visitConstantFieldref(ConstantFieldref obj){
+ tostring = toString(obj);
+ }
+ public void visitConstantFloat(ConstantFloat obj){
+ tostring = toString(obj);
+ }
+ public void visitConstantInteger(ConstantInteger obj){
+ tostring = toString(obj);
+ }
+ public void visitConstantInterfaceMethodref(ConstantInterfaceMethodref obj){
+ tostring = toString(obj);
+ }
+ public void visitConstantLong(ConstantLong obj){
+ tostring = toString(obj);
+ }
+ public void visitConstantMethodref(ConstantMethodref obj){
+ tostring = toString(obj);
+ }
+ public void visitConstantNameAndType(ConstantNameAndType obj){
+ tostring = toString(obj);
+ }
+ public void visitConstantPool(ConstantPool obj){
+ tostring = toString(obj);
+ }
+ public void visitConstantString(ConstantString obj){
+ tostring = toString(obj);
+ }
+ public void visitConstantUtf8(ConstantUtf8 obj){
+ tostring = toString(obj);
+ }
+ public void visitConstantValue(ConstantValue obj){
+ tostring = toString(obj);
+ }
+ public void visitDeprecated(Deprecated obj){
+ tostring = toString(obj);
+ }
+ public void visitExceptionTable(ExceptionTable obj){
+ tostring = toString(obj);
+ }
+ public void visitField(Field obj){
+ tostring = toString(obj);
+ }
+ public void visitInnerClass(InnerClass obj){
+ tostring = toString(obj);
+ }
+ public void visitInnerClasses(InnerClasses obj){
+ tostring = toString(obj);
+ }
+ public void visitJavaClass(JavaClass obj){
+ tostring = toString(obj);
+ }
+ public void visitLineNumber(LineNumber obj){
+ tostring = toString(obj);
+ }
+ public void visitLineNumberTable(LineNumberTable obj){
+ tostring = "<LineNumberTable: "+toString(obj)+">";
+ }
+ public void visitLocalVariable(LocalVariable obj){
+ tostring = toString(obj);
+ }
+ public void visitLocalVariableTable(LocalVariableTable obj){
+ tostring = "<LocalVariableTable: "+toString(obj)+">";
+ }
+ public void visitMethod(Method obj){
+ tostring = toString(obj);
+ }
+ public void visitSourceFile(SourceFile obj){
+ tostring = toString(obj);
+ }
+ public void visitSynthetic(Synthetic obj){
+ tostring = toString(obj);
+ }
+ public void visitUnknown(Unknown obj){
+ tostring = toString(obj);
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/statics/package.html b/src/java/org/apache/bcel/verifier/statics/package.html
new file mode 100644
index 00000000..b86c53b9
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/statics/package.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+$Id$
+-->
+</head>
+<body bgcolor="white">
+
+Provides PassVerifier classes used internally by JustIce. You don't need to bother with them.
+
+<h2>Package Specification</h2>
+
+Contained in this package are PassVerifier classes for use with the JustIce verifier.
+Only the passes performing what Sun calls 'static constraints' have PassVerifier classes
+here.
+
+<h2>Related Documentation</h2>
+
+For a simple demonstration of JustIce working, please see:
+<ul>
+ <li><a href="http://www.inf.fu-berlin.de/~ehaase/cgi-html/Verifier.html">A WWW front-end for JustIce.</a>
+</ul>
+
+</body>
+</html>
diff --git a/src/java/org/apache/bcel/verifier/structurals/ControlFlowGraph.java b/src/java/org/apache/bcel/verifier/structurals/ControlFlowGraph.java
new file mode 100644
index 00000000..e59ceb90
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/structurals/ControlFlowGraph.java
@@ -0,0 +1,466 @@
+package org.apache.bcel.verifier.structurals;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.generic.*;
+import org.apache.bcel.verifier.VerifierFactory;
+import org.apache.bcel.verifier.exc.*;
+import java.util.*;
+
+/**
+ * This class represents a control flow graph of a method.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class ControlFlowGraph{
+
+ /**
+ * Objects of this class represent a node in a ControlFlowGraph.
+ * These nodes are instructions, not basic blocks.
+ */
+ private class InstructionContextImpl implements InstructionContext{
+
+ /**
+ * The TAG field is here for external temporary flagging, such
+ * as graph colouring.
+ *
+ * @see #getTag()
+ * @see #setTag(int)
+ */
+ private int TAG;
+
+ /**
+ * The InstructionHandle this InstructionContext is wrapped around.
+ */
+ private InstructionHandle instruction;
+
+ /**
+ * The 'incoming' execution Frames.
+ */
+ private HashMap inFrames; // key: the last-executed JSR
+
+ /**
+ * The 'outgoing' execution Frames.
+ */
+ private HashMap outFrames; // key: the last-executed JSR
+
+ /**
+ * The 'execution predecessors' - a list of type InstructionContext
+ * of those instances that have been execute()d before in that order.
+ */
+ private ArrayList executionPredecessors = null; // Type: InstructionContext
+
+ /**
+ * Creates an InstructionHandleImpl object from an InstructionHandle.
+ * Creation of one per InstructionHandle suffices. Don't create more.
+ */
+ public InstructionContextImpl(InstructionHandle inst){
+ if (inst == null) throw new AssertionViolatedException("Cannot instantiate InstructionContextImpl from NULL.");
+
+ instruction = inst;
+ inFrames = new java.util.HashMap();
+ outFrames = new java.util.HashMap();
+ }
+
+ /* Satisfies InstructionContext.getTag(). */
+ public int getTag(){
+ return TAG;
+ }
+
+ /* Satisfies InstructionContext.setTag(int). */
+ public void setTag(int tag){
+ TAG = tag;
+ }
+
+ /**
+ * Returns the exception handlers of this instruction.
+ */
+ public ExceptionHandler[] getExceptionHandlers(){
+ return exceptionhandlers.getExceptionHandlers(getInstruction());
+ }
+
+ /**
+ * Returns a clone of the "outgoing" frame situation with respect to the given ExecutionChain.
+ */
+ public Frame getOutFrame(ArrayList execChain){
+ executionPredecessors = execChain;
+
+ Frame org;
+
+ InstructionContext jsr = lastExecutionJSR();
+
+ org = (Frame) outFrames.get(jsr);
+
+ if (org == null){
+ throw new AssertionViolatedException("outFrame not set! This:\n"+this+"\nExecutionChain: "+getExecutionChain()+"\nOutFrames: '"+outFrames+"'.");
+ }
+ return org.getClone();
+ }
+
+ /**
+ * "Merges in" (vmspec2, page 146) the "incoming" frame situation;
+ * executes the instructions symbolically
+ * and therefore calculates the "outgoing" frame situation.
+ * Returns: True iff the "incoming" frame situation changed after
+ * merging with "inFrame".
+ * The execPreds ArrayList must contain the InstructionContext
+ * objects executed so far in the correct order. This is just
+ * one execution path [out of many]. This is needed to correctly
+ * "merge" in the special case of a RET's successor.
+ * <B>The InstConstraintVisitor and ExecutionVisitor instances
+ * must be set up correctly.</B>
+ * @return true - if and only if the "outgoing" frame situation
+ * changed from the one before execute()ing.
+ */
+ public boolean execute(Frame inFrame, ArrayList execPreds, InstConstraintVisitor icv, ExecutionVisitor ev){
+
+ executionPredecessors = (ArrayList) execPreds.clone();
+
+ //sanity check
+ if ( (lastExecutionJSR() == null) && (subroutines.subroutineOf(getInstruction()) != subroutines.getTopLevel() ) ){
+ throw new AssertionViolatedException("Huh?! Am I '"+this+"' part of a subroutine or not?");
+ }
+ if ( (lastExecutionJSR() != null) && (subroutines.subroutineOf(getInstruction()) == subroutines.getTopLevel() ) ){
+ throw new AssertionViolatedException("Huh?! Am I '"+this+"' part of a subroutine or not?");
+ }
+
+ Frame inF = (Frame) inFrames.get(lastExecutionJSR());
+ if (inF == null){// no incoming frame was set, so set it.
+ inFrames.put(lastExecutionJSR(), inFrame);
+ inF = inFrame;
+ }
+ else{// if there was an "old" inFrame
+ if (inF.equals(inFrame)){ //shortcut: no need to merge equal frames.
+ return false;
+ }
+ if (! mergeInFrames(inFrame)){
+ return false;
+ }
+ }
+
+ // Now we're sure the inFrame has changed!
+
+ // new inFrame is already merged in, see above.
+ Frame workingFrame = inF.getClone();
+
+ try{
+ // This verifies the InstructionConstraint for the current
+ // instruction, but does not modify the workingFrame object.
+//InstConstraintVisitor icv = InstConstraintVisitor.getInstance(VerifierFactory.getVerifier(method_gen.getClassName()));
+ icv.setFrame(workingFrame);
+ getInstruction().accept(icv);
+ }
+ catch(StructuralCodeConstraintException ce){
+ ce.extendMessage("","\nInstructionHandle: "+getInstruction()+"\n");
+ ce.extendMessage("","\nExecution Frame:\n"+workingFrame);
+ extendMessageWithFlow(ce);
+ throw ce;
+ }
+
+ // This executes the Instruction.
+ // Therefore the workingFrame object is modified.
+//ExecutionVisitor ev = ExecutionVisitor.getInstance(VerifierFactory.getVerifier(method_gen.getClassName()));
+ ev.setFrame(workingFrame);
+ getInstruction().accept(ev);
+ //getInstruction().accept(ExecutionVisitor.withFrame(workingFrame));
+ outFrames.put(lastExecutionJSR(), workingFrame);
+
+ return true; // new inFrame was different from old inFrame so merging them
+ // yielded a different this.inFrame.
+ }
+
+ /**
+ * Returns a simple String representation of this InstructionContext.
+ */
+ public String toString(){
+ //TODO: Put information in the brackets, e.g.
+ // Is this an ExceptionHandler? Is this a RET? Is this the start of
+ // a subroutine?
+ String ret = getInstruction().toString(false)+"\t[InstructionContext]";
+ return ret;
+ }
+
+ /**
+ * Does the actual merging (vmspec2, page 146).
+ * Returns true IFF this.inFrame was changed in course of merging with inFrame.
+ */
+ private boolean mergeInFrames(Frame inFrame){
+ // TODO: Can be performance-improved.
+ Frame inF = (Frame) inFrames.get(lastExecutionJSR());
+ OperandStack oldstack = inF.getStack().getClone();
+ LocalVariables oldlocals = inF.getLocals().getClone();
+ try{
+ inF.getStack().merge(inFrame.getStack());
+ inF.getLocals().merge(inFrame.getLocals());
+ }
+ catch (StructuralCodeConstraintException sce){
+ extendMessageWithFlow(sce);
+ throw sce;
+ }
+ if ( oldstack.equals(inF.getStack()) &&
+ oldlocals.equals(inF.getLocals()) ){
+ return false;
+ }
+ else{
+ return true;
+ }
+ }
+
+ /**
+ * Returns the control flow execution chain. This is built
+ * while execute(Frame, ArrayList)-ing the code represented
+ * by the surrounding ControlFlowGraph.
+ */
+ private String getExecutionChain(){
+ String s = this.toString();
+ for (int i=executionPredecessors.size()-1; i>=0; i--){
+ s = executionPredecessors.get(i)+"\n" + s;
+ }
+ return s;
+ }
+
+
+ /**
+ * Extends the StructuralCodeConstraintException ("e") object with an at-the-end-extended message.
+ * This extended message will then reflect the execution flow needed to get to the constraint
+ * violation that triggered the throwing of the "e" object.
+ */
+ private void extendMessageWithFlow(StructuralCodeConstraintException e){
+ String s = "Execution flow:\n";
+ e.extendMessage("", s+getExecutionChain());
+ }
+
+ /*
+ * Fulfils the contract of InstructionContext.getInstruction().
+ */
+ public InstructionHandle getInstruction(){
+ return instruction;
+ }
+
+ /**
+ * Returns the InstructionContextImpl with an JSR/JSR_W
+ * that was last in the ExecutionChain, without
+ * a corresponding RET, i.e.
+ * we were called by this one.
+ * Returns null if we were called from the top level.
+ */
+ private InstructionContextImpl lastExecutionJSR(){
+
+ int size = executionPredecessors.size();
+ int retcount = 0;
+
+ for (int i=size-1; i>=0; i--){
+ InstructionContextImpl current = (InstructionContextImpl) (executionPredecessors.get(i));
+ Instruction currentlast = current.getInstruction().getInstruction();
+ if (currentlast instanceof RET) retcount++;
+ if (currentlast instanceof JsrInstruction){
+ retcount--;
+ if (retcount == -1) return current;
+ }
+ }
+ return null;
+ }
+
+ /* Satisfies InstructionContext.getSuccessors(). */
+ public InstructionContext[] getSuccessors(){
+ return contextsOf(_getSuccessors());
+ }
+
+ /**
+ * A utility method that calculates the successors of a given InstructionHandle
+ * That means, a RET does have successors as defined here.
+ * A JsrInstruction has its target as its successor
+ * (opposed to its physical successor) as defined here.
+ */
+// TODO: implement caching!
+ private InstructionHandle[] _getSuccessors(){
+ final InstructionHandle[] empty = new InstructionHandle[0];
+ final InstructionHandle[] single = new InstructionHandle[1];
+ final InstructionHandle[] pair = new InstructionHandle[2];
+
+ Instruction inst = getInstruction().getInstruction();
+
+ if (inst instanceof RET){
+ Subroutine s = subroutines.subroutineOf(getInstruction());
+ if (s==null){ //return empty; // RET in dead code. "empty" would be the correct answer, but we know something about the surrounding project...
+ throw new AssertionViolatedException("Asking for successors of a RET in dead code?!");
+ }
+//TODO: remove
+throw new AssertionViolatedException("DID YOU REALLY WANT TO ASK FOR RET'S SUCCS?");
+/*
+ InstructionHandle[] jsrs = s.getEnteringJsrInstructions();
+ InstructionHandle[] ret = new InstructionHandle[jsrs.length];
+ for (int i=0; i<jsrs.length; i++){
+ ret[i] = jsrs[i].getNext();
+ }
+ return ret;
+*/
+ }
+
+ // Terminates method normally.
+ if (inst instanceof ReturnInstruction){
+ return empty;
+ }
+
+ // Terminates method abnormally, because JustIce mandates
+ // subroutines not to be protected by exception handlers.
+ if (inst instanceof ATHROW){
+ return empty;
+ }
+
+ // See method comment.
+ if (inst instanceof JsrInstruction){
+ single[0] = ((JsrInstruction) inst).getTarget();
+ return single;
+ }
+
+ if (inst instanceof GotoInstruction){
+ single[0] = ((GotoInstruction) inst).getTarget();
+ return single;
+ }
+
+ if (inst instanceof BranchInstruction){
+ if (inst instanceof Select){
+ // BCEL's getTargets() returns only the non-default targets,
+ // thanks to Eli Tilevich for reporting.
+ InstructionHandle[] matchTargets = ((Select) inst).getTargets();
+ InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1];
+ ret[0] = ((Select) inst).getTarget();
+ System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length);
+ return ret;
+ }
+ else{
+ pair[0] = getInstruction().getNext();
+ pair[1] = ((BranchInstruction) inst).getTarget();
+ return pair;
+ }
+ }
+
+ // default case: Fall through.
+ single[0] = getInstruction().getNext();
+ return single;
+ }
+
+ } // End Inner InstructionContextImpl Class.
+
+ /** The MethofGen object we're working on. */
+ private final MethodGen method_gen;
+
+ /** The Subroutines object for the method whose control flow is represented by this ControlFlowGraph. */
+ private final Subroutines subroutines;
+
+ /** The ExceptionHandlers object for the method whose control flow is represented by this ControlFlowGraph. */
+ private final ExceptionHandlers exceptionhandlers;
+
+ /** All InstructionContext instances of this ControlFlowGraph. */
+ private Hashtable instructionContexts = new Hashtable(); //keys: InstructionHandle, values: InstructionContextImpl
+
+ /**
+ * A Control Flow Graph.
+ */
+ public ControlFlowGraph(MethodGen method_gen){
+ subroutines = new Subroutines(method_gen);
+ exceptionhandlers = new ExceptionHandlers(method_gen);
+
+ InstructionHandle[] instructionhandles = method_gen.getInstructionList().getInstructionHandles();
+ for (int i=0; i<instructionhandles.length; i++){
+ instructionContexts.put(instructionhandles[i], new InstructionContextImpl(instructionhandles[i]));
+ }
+
+ this.method_gen = method_gen;
+ }
+
+ /**
+ * Returns the InstructionContext of a given instruction.
+ */
+ public InstructionContext contextOf(InstructionHandle inst){
+ InstructionContext ic = (InstructionContext) instructionContexts.get(inst);
+ if (ic == null){
+ throw new AssertionViolatedException("InstructionContext requested for an InstructionHandle that's not known!");
+ }
+ return ic;
+ }
+
+ /**
+ * Returns the InstructionContext[] of a given InstructionHandle[],
+ * in a naturally ordered manner.
+ */
+ public InstructionContext[] contextsOf(InstructionHandle[] insts){
+ InstructionContext[] ret = new InstructionContext[insts.length];
+ for (int i=0; i<insts.length; i++){
+ ret[i] = contextOf(insts[i]);
+ }
+ return ret;
+ }
+
+ /**
+ * Returns an InstructionContext[] with all the InstructionContext instances
+ * for the method whose control flow is represented by this ControlFlowGraph
+ * <B>(NOT ORDERED!)</B>.
+ */
+ public InstructionContext[] getInstructionContexts(){
+ InstructionContext[] ret = new InstructionContext[instructionContexts.values().size()];
+ return (InstructionContext[]) instructionContexts.values().toArray(ret);
+ }
+
+ /**
+ * Returns true, if and only if the said instruction is not reachable; that means,
+ * if it not part of this ControlFlowGraph.
+ */
+ public boolean isDead(InstructionHandle i){
+ return instructionContexts.containsKey(i);
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/structurals/ExceptionHandler.java b/src/java/org/apache/bcel/verifier/structurals/ExceptionHandler.java
new file mode 100644
index 00000000..b05040b3
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/structurals/ExceptionHandler.java
@@ -0,0 +1,93 @@
+package org.apache.bcel.verifier.structurals;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.generic.*;
+
+/**
+ * This class represents an exception handler; that is, an ObjectType
+ * representing a subclass of java.lang.Throwable and the instruction
+ * the handler starts off (represented by an InstructionContext).
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class ExceptionHandler{
+ /** The type of the exception to catch. NULL means ANY. */
+ private ObjectType catchtype;
+
+ /** The InstructionHandle where the handling begins. */
+ private InstructionHandle handlerpc;
+
+ /** Leave instance creation to JustIce. */
+ ExceptionHandler(ObjectType catch_type, InstructionHandle handler_pc){
+ catchtype = catch_type;
+ handlerpc = handler_pc;
+ }
+
+ /**
+ * Returns the type of the exception that's handled. <B>'null' means 'ANY'.</B>
+ */
+ public ObjectType getExceptionType(){
+ return catchtype;
+ }
+
+ /**
+ * Returns the InstructionHandle where the handler starts off.
+ */
+ public InstructionHandle getHandlerStart(){
+ return handlerpc;
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/structurals/ExceptionHandlers.java b/src/java/org/apache/bcel/verifier/structurals/ExceptionHandlers.java
new file mode 100644
index 00000000..ebf95e69
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/structurals/ExceptionHandlers.java
@@ -0,0 +1,107 @@
+package org.apache.bcel.verifier.structurals;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.generic.*;
+import java.util.HashSet;
+import java.util.Hashtable;
+
+/**
+ * This class allows easy access to ExceptionHandler objects.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class ExceptionHandlers{
+ /**
+ * The ExceptionHandler instances.
+ * Key: InstructionHandle objects, Values: HashSet<ExceptionHandler> instances.
+ */
+ private Hashtable exceptionhandlers;
+
+ /**
+ * Constructor. Creates a new ExceptionHandlers instance.
+ */
+ public ExceptionHandlers(MethodGen mg){
+ exceptionhandlers = new Hashtable();
+ CodeExceptionGen[] cegs = mg.getExceptionHandlers();
+ for (int i=0; i<cegs.length; i++){
+ ExceptionHandler eh = new ExceptionHandler(cegs[i].getCatchType(), cegs[i].getHandlerPC());
+ for (InstructionHandle ih=cegs[i].getStartPC(); ih != cegs[i].getEndPC().getNext(); ih=ih.getNext()){
+ HashSet hs;
+ hs = (HashSet) exceptionhandlers.get(ih);
+ if (hs == null){
+ hs = new HashSet();
+ exceptionhandlers.put(ih, hs);
+ }
+ hs.add(eh);
+ }
+ }
+ }
+
+ /**
+ * Returns all the ExceptionHandler instances representing exception
+ * handlers that protect the instruction ih.
+ */
+ public ExceptionHandler[] getExceptionHandlers(InstructionHandle ih){
+ HashSet hs = (HashSet) exceptionhandlers.get(ih);
+ if (hs == null) return new ExceptionHandler[0];
+ else{
+ ExceptionHandler[] ret = new ExceptionHandler[hs.size()];
+ return (ExceptionHandler[]) (hs.toArray(ret));
+ }
+ }
+
+}
diff --git a/src/java/org/apache/bcel/verifier/structurals/ExecutionVisitor.java b/src/java/org/apache/bcel/verifier/structurals/ExecutionVisitor.java
new file mode 100644
index 00000000..330f3a2f
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/structurals/ExecutionVisitor.java
@@ -0,0 +1,1126 @@
+package org.apache.bcel.verifier.structurals;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.Constants;
+import org.apache.bcel.Repository;
+import org.apache.bcel.generic.*;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.classfile.Constant;
+import org.apache.bcel.classfile.ConstantDouble;
+import org.apache.bcel.classfile.ConstantFloat;
+import org.apache.bcel.classfile.ConstantInteger;
+import org.apache.bcel.classfile.ConstantLong;
+import org.apache.bcel.classfile.ConstantString;
+import org.apache.bcel.verifier.Verifier;
+import org.apache.bcel.verifier.exc.*;
+import java.util.ArrayList;
+import java.util.Hashtable;
+
+/**
+ * This Visitor class may be used for a type-based Java Virtual Machine
+ * simulation.
+ * It does not check for correct types on the OperandStack or in the
+ * LocalVariables; nor does it check their sizes are sufficiently big.
+ * Thus, to use this Visitor for bytecode verifying, you have to make sure
+ * externally that the type constraints of the Java Virtual Machine instructions
+ * are satisfied. An InstConstraintVisitor may be used for this.
+ * Anyway, this Visitor does not mandate it. For example, when you
+ * visitIADD(IADD o), then there are two stack slots popped and one
+ * stack slot containing a Type.INT is pushed (where you could also
+ * pop only one slot if you know there are two Type.INT on top of the
+ * stack). Monitor-specific behaviour is not simulated.
+ *
+ * </P><B>Conventions:</B>
+ *
+ * Type.VOID will never be pushed onto the stack. Type.DOUBLE and Type.LONG
+ * that would normally take up two stack slots (like Double_HIGH and
+ * Double_LOW) are represented by a simple single Type.DOUBLE or Type.LONG
+ * object on the stack here.
+ * If a two-slot type is stored into a local variable, the next variable
+ * is given the type Type.UNKNOWN.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ * @see #visitDSTORE(DSTORE o)
+ * @see InstConstraintVisitor
+ */
+public class ExecutionVisitor extends EmptyVisitor implements Visitor{
+
+ /**
+ * The executionframe we're operating on.
+ */
+ private Frame frame = null;
+
+ /**
+ * The ConstantPoolGen we're working with.
+ * @see #setConstantPoolGen(ConstantPoolGen)
+ */
+ private ConstantPoolGen cpg = null;
+
+ /**
+ * Constructor. Constructs a new instance of this class.
+ */
+ public ExecutionVisitor(){}
+
+ /**
+ * The OperandStack from the current Frame we're operating on.
+ * @see #setFrame(Frame)
+ */
+ private OperandStack stack(){
+ return frame.getStack();
+ }
+
+ /**
+ * The LocalVariables from the current Frame we're operating on.
+ * @see #setFrame(Frame)
+ */
+ private LocalVariables locals(){
+ return frame.getLocals();
+ }
+
+ /**
+ * Sets the ConstantPoolGen needed for symbolic execution.
+ */
+ public void setConstantPoolGen(ConstantPoolGen cpg){
+ this.cpg = cpg;
+ }
+
+ /**
+ * The only method granting access to the single instance of
+ * the ExecutionVisitor class. Before actively using this
+ * instance, <B>SET THE ConstantPoolGen FIRST</B>.
+ * @see #setConstantPoolGen(ConstantPoolGen)
+ */
+ public void setFrame(Frame f){
+ this.frame = f;
+ }
+
+ ///** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ //public void visitWIDE(WIDE o){
+ // The WIDE instruction is modelled as a flag
+ // of the embedded instructions in BCEL.
+ // Therefore BCEL checks for possible errors
+ // when parsing in the .class file: We don't
+ // have even the possibilty to care for WIDE
+ // here.
+ //}
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitAALOAD(AALOAD o){
+ stack().pop(); // pop the index int
+//System.out.print(stack().peek());
+ Type t = stack().pop(); // Pop Array type
+ if (t == Type.NULL){
+ stack().push(Type.NULL);
+ } // Do nothing stackwise --- a NullPointerException is thrown at Run-Time
+ else{
+ ArrayType at = (ArrayType) t;
+ stack().push(at.getElementType());
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitAASTORE(AASTORE o){
+ stack().pop();
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitACONST_NULL(ACONST_NULL o){
+ stack().push(Type.NULL);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitALOAD(ALOAD o){
+ stack().push(locals().get(o.getIndex()));
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitANEWARRAY(ANEWARRAY o){
+ stack().pop(); //count
+ stack().push( new ArrayType(o.getType(cpg), 1) );
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitARETURN(ARETURN o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitARRAYLENGTH(ARRAYLENGTH o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitASTORE(ASTORE o){
+ locals().set(o.getIndex(), stack().pop());
+ //System.err.println("TODO-DEBUG: set LV '"+o.getIndex()+"' to '"+locals().get(o.getIndex())+"'.");
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitATHROW(ATHROW o){
+ Type t = stack().pop();
+ stack().clear();
+ if (t.equals(Type.NULL))
+ stack().push(Type.getType("Ljava/lang/NullPointerException;"));
+ else
+ stack().push(t);
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitBALOAD(BALOAD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitBASTORE(BASTORE o){
+ stack().pop();
+ stack().pop();
+ stack().pop();
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitBIPUSH(BIPUSH o){
+ stack().push(Type.INT);
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitCALOAD(CALOAD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitCASTORE(CASTORE o){
+ stack().pop();
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitCHECKCAST(CHECKCAST o){
+ // It's possibly wrong to do so, but SUN's
+ // ByteCode verifier seems to do (only) this, too.
+ // TODO: One could use a sophisticated analysis here to check
+ // if a type cannot possibly be cated to another and by
+ // so doing predict the ClassCastException at run-time.
+ stack().pop();
+ stack().push(o.getType(cpg));
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitD2F(D2F o){
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitD2I(D2I o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitD2L(D2L o){
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDADD(DADD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDALOAD(DALOAD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDASTORE(DASTORE o){
+ stack().pop();
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDCMPG(DCMPG o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDCMPL(DCMPL o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDCONST(DCONST o){
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDDIV(DDIV o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDLOAD(DLOAD o){
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDMUL(DMUL o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDNEG(DNEG o){
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDREM(DREM o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDRETURN(DRETURN o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDSTORE(DSTORE o){
+ locals().set(o.getIndex(), stack().pop());
+ locals().set(o.getIndex()+1, Type.UNKNOWN);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDSUB(DSUB o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDUP(DUP o){
+ Type t = stack().pop();
+ stack().push(t);
+ stack().push(t);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDUP_X1(DUP_X1 o){
+ Type w1 = stack().pop();
+ Type w2 = stack().pop();
+ stack().push(w1);
+ stack().push(w2);
+ stack().push(w1);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDUP_X2(DUP_X2 o){
+ Type w1 = stack().pop();
+ Type w2 = stack().pop();
+ if (w2.getSize() == 2){
+ stack().push(w1);
+ stack().push(w2);
+ stack().push(w1);
+ }
+ else{
+ Type w3 = stack().pop();
+ stack().push(w1);
+ stack().push(w3);
+ stack().push(w2);
+ stack().push(w1);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDUP2(DUP2 o){
+ Type t = stack().pop();
+ if (t.getSize() == 2){
+ stack().push(t);
+ stack().push(t);
+ }
+ else{ // t.getSize() is 1
+ Type u = stack().pop();
+ stack().push(u);
+ stack().push(t);
+ stack().push(u);
+ stack().push(t);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDUP2_X1(DUP2_X1 o){
+ Type t = stack().pop();
+ if (t.getSize() == 2){
+ Type u = stack().pop();
+ stack().push(t);
+ stack().push(u);
+ stack().push(t);
+ }
+ else{ //t.getSize() is1
+ Type u = stack().pop();
+ Type v = stack().pop();
+ stack().push(u);
+ stack().push(t);
+ stack().push(v);
+ stack().push(u);
+ stack().push(t);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDUP2_X2(DUP2_X2 o){
+ Type t = stack().pop();
+ if (t.getSize() == 2){
+ Type u = stack().pop();
+ if (u.getSize() == 2){
+ stack().push(t);
+ stack().push(u);
+ stack().push(t);
+ }else{
+ Type v = stack().pop();
+ stack().push(t);
+ stack().push(v);
+ stack().push(u);
+ stack().push(t);
+ }
+ }
+ else{ //t.getSize() is 1
+ Type u = stack().pop();
+ Type v = stack().pop();
+ if (v.getSize() == 2){
+ stack().push(u);
+ stack().push(t);
+ stack().push(v);
+ stack().push(u);
+ stack().push(t);
+ }else{
+ Type w = stack().pop();
+ stack().push(u);
+ stack().push(t);
+ stack().push(w);
+ stack().push(v);
+ stack().push(u);
+ stack().push(t);
+ }
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitF2D(F2D o){
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitF2I(F2I o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitF2L(F2L o){
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFADD(FADD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFALOAD(FALOAD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFASTORE(FASTORE o){
+ stack().pop();
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFCMPG(FCMPG o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFCMPL(FCMPL o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFCONST(FCONST o){
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFDIV(FDIV o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFLOAD(FLOAD o){
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFMUL(FMUL o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFNEG(FNEG o){
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFREM(FREM o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFRETURN(FRETURN o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFSTORE(FSTORE o){
+ locals().set(o.getIndex(), stack().pop());
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFSUB(FSUB o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitGETFIELD(GETFIELD o){
+ stack().pop();
+ Type t = o.getFieldType(cpg);
+ if ( t.equals(Type.BOOLEAN) ||
+ t.equals(Type.CHAR) ||
+ t.equals(Type.BYTE) ||
+ t.equals(Type.SHORT) )
+ t = Type.INT;
+ stack().push(t);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitGETSTATIC(GETSTATIC o){
+ Type t = o.getFieldType(cpg);
+ if ( t.equals(Type.BOOLEAN) ||
+ t.equals(Type.CHAR) ||
+ t.equals(Type.BYTE) ||
+ t.equals(Type.SHORT) )
+ t = Type.INT;
+ stack().push(t);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitGOTO(GOTO o){
+ // no stack changes.
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitGOTO_W(GOTO_W o){
+ // no stack changes.
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitI2B(I2B o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitI2C(I2C o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitI2D(I2D o){
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitI2F(I2F o){
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitI2L(I2L o){
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitI2S(I2S o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIADD(IADD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIALOAD(IALOAD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIAND(IAND o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIASTORE(IASTORE o){
+ stack().pop();
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitICONST(ICONST o){
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIDIV(IDIV o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIF_ACMPEQ(IF_ACMPEQ o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIF_ACMPNE(IF_ACMPNE o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIF_ICMPEQ(IF_ICMPEQ o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIF_ICMPGE(IF_ICMPGE o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIF_ICMPGT(IF_ICMPGT o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIF_ICMPLE(IF_ICMPLE o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIF_ICMPLT(IF_ICMPLT o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIF_ICMPNE(IF_ICMPNE o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIFEQ(IFEQ o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIFGE(IFGE o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIFGT(IFGT o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIFLE(IFLE o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIFLT(IFLT o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIFNE(IFNE o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIFNONNULL(IFNONNULL o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIFNULL(IFNULL o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIINC(IINC o){
+ // stack is not changed.
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitILOAD(ILOAD o){
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIMUL(IMUL o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitINEG(INEG o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitINSTANCEOF(INSTANCEOF o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitINVOKEINTERFACE(INVOKEINTERFACE o){
+ stack().pop(); //objectref
+ for (int i=0; i<o.getArgumentTypes(cpg).length; i++){
+ stack().pop();
+ }
+ // We are sure the invoked method will xRETURN eventually
+ // We simulate xRETURNs functionality here because we
+ // don't really "jump into" and simulate the invoked
+ // method.
+ if (o.getReturnType(cpg) != Type.VOID){
+ Type t = o.getReturnType(cpg);
+ if ( t.equals(Type.BOOLEAN) ||
+ t.equals(Type.CHAR) ||
+ t.equals(Type.BYTE) ||
+ t.equals(Type.SHORT) )
+ t = Type.INT;
+ stack().push(t);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitINVOKESPECIAL(INVOKESPECIAL o){
+ if (o.getMethodName(cpg).equals(Constants.CONSTRUCTOR_NAME)){
+ UninitializedObjectType t = (UninitializedObjectType) stack().peek(o.getArgumentTypes(cpg).length);
+ if (t == frame._this){
+ frame._this = null;
+ }
+ stack().initializeObject(t);
+ locals().initializeObject(t);
+ }
+ stack().pop(); //objectref
+ for (int i=0; i<o.getArgumentTypes(cpg).length; i++){
+ stack().pop();
+ }
+ // We are sure the invoked method will xRETURN eventually
+ // We simulate xRETURNs functionality here because we
+ // don't really "jump into" and simulate the invoked
+ // method.
+ if (o.getReturnType(cpg) != Type.VOID){
+ Type t = o.getReturnType(cpg);
+ if ( t.equals(Type.BOOLEAN) ||
+ t.equals(Type.CHAR) ||
+ t.equals(Type.BYTE) ||
+ t.equals(Type.SHORT) )
+ t = Type.INT;
+ stack().push(t);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitINVOKESTATIC(INVOKESTATIC o){
+ for (int i=0; i<o.getArgumentTypes(cpg).length; i++){
+ stack().pop();
+ }
+ // We are sure the invoked method will xRETURN eventually
+ // We simulate xRETURNs functionality here because we
+ // don't really "jump into" and simulate the invoked
+ // method.
+ if (o.getReturnType(cpg) != Type.VOID){
+ Type t = o.getReturnType(cpg);
+ if ( t.equals(Type.BOOLEAN) ||
+ t.equals(Type.CHAR) ||
+ t.equals(Type.BYTE) ||
+ t.equals(Type.SHORT) )
+ t = Type.INT;
+ stack().push(t);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitINVOKEVIRTUAL(INVOKEVIRTUAL o){
+ stack().pop(); //objectref
+ for (int i=0; i<o.getArgumentTypes(cpg).length; i++){
+ stack().pop();
+ }
+ // We are sure the invoked method will xRETURN eventually
+ // We simulate xRETURNs functionality here because we
+ // don't really "jump into" and simulate the invoked
+ // method.
+ if (o.getReturnType(cpg) != Type.VOID){
+ Type t = o.getReturnType(cpg);
+ if ( t.equals(Type.BOOLEAN) ||
+ t.equals(Type.CHAR) ||
+ t.equals(Type.BYTE) ||
+ t.equals(Type.SHORT) )
+ t = Type.INT;
+ stack().push(t);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIOR(IOR o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIREM(IREM o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIRETURN(IRETURN o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitISHL(ISHL o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitISHR(ISHR o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitISTORE(ISTORE o){
+ locals().set(o.getIndex(), stack().pop());
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitISUB(ISUB o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIUSHR(IUSHR o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIXOR(IXOR o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitJSR(JSR o){
+ stack().push(new ReturnaddressType(o.physicalSuccessor()));
+//System.err.println("TODO-----------:"+o.physicalSuccessor());
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitJSR_W(JSR_W o){
+ stack().push(new ReturnaddressType(o.physicalSuccessor()));
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitL2D(L2D o){
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitL2F(L2F o){
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitL2I(L2I o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLADD(LADD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLALOAD(LALOAD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLAND(LAND o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLASTORE(LASTORE o){
+ stack().pop();
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLCMP(LCMP o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLCONST(LCONST o){
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLDC(LDC o){
+ Constant c = cpg.getConstant(o.getIndex());
+ if (c instanceof ConstantInteger){
+ stack().push(Type.INT);
+ }
+ if (c instanceof ConstantFloat){
+ stack().push(Type.FLOAT);
+ }
+ if (c instanceof ConstantString){
+ stack().push(Type.STRING);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLDC_W(LDC_W o){
+ Constant c = cpg.getConstant(o.getIndex());
+ if (c instanceof ConstantInteger){
+ stack().push(Type.INT);
+ }
+ if (c instanceof ConstantFloat){
+ stack().push(Type.FLOAT);
+ }
+ if (c instanceof ConstantString){
+ stack().push(Type.STRING);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLDC2_W(LDC2_W o){
+ Constant c = cpg.getConstant(o.getIndex());
+ if (c instanceof ConstantLong){
+ stack().push(Type.LONG);
+ }
+ if (c instanceof ConstantDouble){
+ stack().push(Type.DOUBLE);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLDIV(LDIV o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLLOAD(LLOAD o){
+ stack().push(locals().get(o.getIndex()));
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLMUL(LMUL o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLNEG(LNEG o){
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLOOKUPSWITCH(LOOKUPSWITCH o){
+ stack().pop(); //key
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLOR(LOR o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLREM(LREM o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLRETURN(LRETURN o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLSHL(LSHL o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLSHR(LSHR o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLSTORE(LSTORE o){
+ locals().set(o.getIndex(), stack().pop());
+ locals().set(o.getIndex()+1, Type.UNKNOWN);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLSUB(LSUB o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLUSHR(LUSHR o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLXOR(LXOR o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitMONITORENTER(MONITORENTER o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitMONITOREXIT(MONITOREXIT o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitMULTIANEWARRAY(MULTIANEWARRAY o){
+ for (int i=0; i<o.getDimensions(); i++){
+ stack().pop();
+ }
+ stack().push(o.getType(cpg));
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitNEW(NEW o){
+ stack().push(new UninitializedObjectType((ObjectType) (o.getType(cpg))));
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitNEWARRAY(NEWARRAY o){
+ stack().pop();
+ stack().push(o.getType());
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitNOP(NOP o){
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitPOP(POP o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitPOP2(POP2 o){
+ Type t = stack().pop();
+ if (t.getSize() == 1){
+ stack().pop();
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitPUTFIELD(PUTFIELD o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitPUTSTATIC(PUTSTATIC o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitRET(RET o){
+ // do nothing, return address
+ // is in in the local variables.
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitRETURN(RETURN o){
+ // do nothing.
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitSALOAD(SALOAD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitSASTORE(SASTORE o){
+ stack().pop();
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitSIPUSH(SIPUSH o){
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitSWAP(SWAP o){
+ Type t = stack().pop();
+ Type u = stack().pop();
+ stack().push(t);
+ stack().push(u);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitTABLESWITCH(TABLESWITCH o){
+ stack().pop();
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/structurals/Frame.java b/src/java/org/apache/bcel/verifier/structurals/Frame.java
new file mode 100644
index 00000000..cfff00f5
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/structurals/Frame.java
@@ -0,0 +1,153 @@
+package org.apache.bcel.verifier.structurals;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.generic.*;
+import org.apache.bcel.verifier.exc.*;
+import java.util.ArrayList;
+
+/**
+ * This class represents a JVM execution frame; that means,
+ * a local variable array and an operand stack.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+
+public class Frame{
+
+ /**
+ * For instance initialization methods, it is important to remember
+ * which instance it is that is not initialized yet. It will be
+ * initialized invoking another constructor later.
+ * NULL means the instance already *is* initialized.
+ */
+ protected static UninitializedObjectType _this;
+
+ /**
+ *
+ */
+ private LocalVariables locals;
+
+ /**
+ *
+ */
+ private OperandStack stack;
+
+ /**
+ *
+ */
+ public Frame(int maxLocals, int maxStack){
+ locals = new LocalVariables(maxLocals);
+ stack = new OperandStack(maxStack);
+ }
+
+ /**
+ *
+ */
+ public Frame(LocalVariables locals, OperandStack stack){
+ this.locals = locals;
+ this.stack = stack;
+ }
+
+ /**
+ *
+ */
+ protected Object clone(){
+ Frame f = new Frame(locals.getClone(), stack.getClone());
+ return f;
+ }
+
+ /**
+ *
+ */
+ public Frame getClone(){
+ return (Frame) clone();
+ }
+
+ /**
+ *
+ */
+ public LocalVariables getLocals(){
+ return locals;
+ }
+
+ /**
+ *
+ */
+ public OperandStack getStack(){
+ return stack;
+ }
+
+ /**
+ *
+ */
+ public boolean equals(Object o){
+ if (!(o instanceof Frame)) return false; // implies "null" is non-equal.
+ Frame f = (Frame) o;
+ return this.stack.equals(f.stack) && this.locals.equals(f.locals);
+ }
+
+ /**
+ * Returns a String representation of the Frame instance.
+ */
+ public String toString(){
+ String s="Local Variables:\n";
+ s += locals;
+ s += "OperandStack:\n";
+ s += stack;
+ return s;
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/structurals/GenericArray.java b/src/java/org/apache/bcel/verifier/structurals/GenericArray.java
new file mode 100644
index 00000000..30cdafe6
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/structurals/GenericArray.java
@@ -0,0 +1,66 @@
+package org.apache.bcel.verifier.structurals;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/**
+ * A placeholder class that can be used to create an ObjectType of which
+ * has some of the properties arrays have. They implement java.lang.Cloneable
+ * and java.io.Serializable and they extend java.lang.Object.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class GenericArray extends java.lang.Object implements java.lang.Cloneable, java.io.Serializable{
+}
diff --git a/src/java/org/apache/bcel/verifier/structurals/InstConstraintVisitor.java b/src/java/org/apache/bcel/verifier/structurals/InstConstraintVisitor.java
new file mode 100644
index 00000000..05c999ad
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/structurals/InstConstraintVisitor.java
@@ -0,0 +1,2652 @@
+package org.apache.bcel.verifier.structurals;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.Constants;
+import org.apache.bcel.Repository;
+import org.apache.bcel.classfile.Constant;
+import org.apache.bcel.classfile.ConstantClass;
+import org.apache.bcel.classfile.ConstantDouble;
+import org.apache.bcel.classfile.ConstantInteger;
+import org.apache.bcel.classfile.ConstantFieldref;
+import org.apache.bcel.classfile.ConstantFloat;
+import org.apache.bcel.classfile.ConstantInterfaceMethodref;
+import org.apache.bcel.classfile.ConstantLong;
+import org.apache.bcel.classfile.ConstantNameAndType;
+import org.apache.bcel.classfile.ConstantString;
+import org.apache.bcel.classfile.ConstantUtf8;
+import org.apache.bcel.classfile.Field;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.generic.*;
+import org.apache.bcel.verifier.*;
+import org.apache.bcel.verifier.exc.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+
+/**
+ * A Visitor class testing for valid preconditions of JVM instructions.
+ * The instance of this class will throw a StructuralCodeConstraintException
+ * instance if an instruction is visitXXX()ed which has preconditions that are
+ * not satisfied.
+ * TODO: Currently, the JVM's behaviour concerning monitors (MONITORENTER,
+ * MONITOREXIT) is not modeled in JustIce.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ * @see org.apache.bcel.verifier.exc.StructuralCodeConstraintException
+ * @see org.apache.bcel.verifier.exc.LinkingConstraintException
+ */
+public class InstConstraintVisitor extends EmptyVisitor implements org.apache.bcel.generic.Visitor{
+
+ private static ObjectType GENERIC_ARRAY = new ObjectType("org.apache.bcel.verifier.structurals.GenericArray");
+
+ /**
+ * The constructor. Constructs a new instance of this class.
+ */
+ public InstConstraintVisitor(){}
+
+ /**
+ * The Execution Frame we're working on.
+ *
+ * @see #setFrame(Frame f)
+ * @see #locals()
+ * @see #stack()
+ */
+ private Frame frame = null;
+
+ /**
+ * The ConstantPoolGen we're working on.
+ *
+ * @see #setConstantPoolGen(ConstantPoolGen cpg)
+ */
+ private ConstantPoolGen cpg = null;
+
+ /**
+ * The MethodGen we're working on.
+ *
+ * @see #setMethodGen(MethodGen mg)
+ */
+ private MethodGen mg = null;
+
+ /**
+ * The OperandStack we're working on.
+ *
+ * @see #setFrame(Frame f)
+ */
+ private OperandStack stack(){
+ return frame.getStack();
+ }
+
+ /**
+ * The LocalVariables we're working on.
+ *
+ * @see #setFrame(Frame f)
+ */
+ private LocalVariables locals(){
+ return frame.getLocals();
+ }
+
+ /**
+ * This method is called by the visitXXX() to notify the acceptor of this InstConstraintVisitor
+ * that a constraint violation has occured. This is done by throwing an instance of a
+ * StructuralCodeConstraintException.
+ * @throws org.apache.bcel.verifier.exc.StructuralCodeConstraintException always.
+ */
+ private void constraintViolated(Instruction violator, String description){
+ String fq_classname = violator.getClass().getName();
+ throw new StructuralCodeConstraintException("Instruction "+ fq_classname.substring(fq_classname.lastIndexOf('.')+1) +" constraint violated: " + description);
+ }
+
+ /**
+ * This returns the single instance of the InstConstraintVisitor class.
+ * To operate correctly, other values must have been set before actually
+ * using the instance.
+ * Use this method for performance reasons.
+ *
+ * @see #setConstantPoolGen(ConstantPoolGen cpg)
+ * @see #setMethodGen(MethodGen mg)
+ */
+ public void setFrame(Frame f){
+ this.frame = f;
+ //if (singleInstance.mg == null || singleInstance.cpg == null) throw new AssertionViolatedException("Forgot to set important values first.");
+ }
+
+ /**
+ * Sets the ConstantPoolGen instance needed for constraint
+ * checking prior to execution.
+ */
+ public void setConstantPoolGen(ConstantPoolGen cpg){
+ this.cpg = cpg;
+ }
+
+ /**
+ * Sets the MethodGen instance needed for constraint
+ * checking prior to execution.
+ */
+ public void setMethodGen(MethodGen mg){
+ this.mg = mg;
+ }
+
+ /**
+ * Assures index is of type INT.
+ * @throws org.apache.bcel.verifier.exc.StructuralCodeConstraintException if the above constraint is not satisfied.
+ */
+ private void indexOfInt(Instruction o, Type index){
+ if (! index.equals(Type.INT))
+ constraintViolated(o, "The 'index' is not of type int but of type "+index+".");
+ }
+
+ /**
+ * Assures the ReferenceType r is initialized (or Type.NULL).
+ * Formally, this means (!(r instanceof UninitializedObjectType)), because
+ * there are no uninitialized array types.
+ * @throws org.apache.bcel.verifier.exc.StructuralCodeConstraintException if the above constraint is not satisfied.
+ */
+ private void referenceTypeIsInitialized(Instruction o, ReferenceType r){
+ if (r instanceof UninitializedObjectType){
+ constraintViolated(o, "Working on an uninitialized object '"+r+"'.");
+ }
+ }
+
+ /** Assures value is of type INT. */
+ private void valueOfInt(Instruction o, Type value){
+ if (! value.equals(Type.INT))
+ constraintViolated(o, "The 'value' is not of type int but of type "+value+".");
+ }
+
+ /**
+ * Assures arrayref is of ArrayType or NULL;
+ * returns true if and only if arrayref is non-NULL.
+ * @throws org.apache.bcel.verifier.exc.StructuralCodeConstraintException if the above constraint is violated.
+ */
+ private boolean arrayrefOfArrayType(Instruction o, Type arrayref){
+ if (! ((arrayref instanceof ArrayType) || arrayref.equals(Type.NULL)) )
+ constraintViolated(o, "The 'arrayref' does not refer to an array but is of type "+arrayref+".");
+ return (arrayref instanceof ArrayType);
+ }
+
+ /***************************************************************/
+ /* MISC */
+ /***************************************************************/
+ /**
+ * Ensures the general preconditions of an instruction that accesses the stack.
+ * This method is here because BCEL has no such superinterface for the stack
+ * accessing instructions; and there are funny unexpected exceptions in the
+ * semantices of the superinterfaces and superclasses provided.
+ * E.g. SWAP is a StackConsumer, but DUP_X1 is not a StackProducer.
+ * Therefore, this method is called by all StackProducer, StackConsumer,
+ * and StackInstruction instances via their visitXXX() method.
+ * Unfortunately, as the superclasses and superinterfaces overlap, some instructions
+ * cause this method to be called two or three times. [TODO: Fix this.]
+ *
+ * @see #visitStackConsumer(StackConsumer o)
+ * @see #visitStackProducer(StackProducer o)
+ * @see #visitStackInstruction(StackInstruction o)
+ */
+ private void _visitStackAccessor(Instruction o){
+ int consume = o.consumeStack(cpg); // Stack values are always consumed first; then produced.
+ if (consume > stack().slotsUsed()){
+ constraintViolated((Instruction) o, "Cannot consume "+consume+" stack slots: only "+stack().slotsUsed()+" slot(s) left on stack!\nStack:\n"+stack());
+ }
+
+ int produce = o.produceStack(cpg) - ((Instruction) o).consumeStack(cpg); // Stack values are always consumed first; then produced.
+ if ( produce + stack().slotsUsed() > stack().maxStack() ){
+ constraintViolated((Instruction) o, "Cannot produce "+produce+" stack slots: only "+(stack().maxStack()-stack().slotsUsed())+" free stack slot(s) left.\nStack:\n"+stack());
+ }
+ }
+
+ /***************************************************************/
+ /* "generic"visitXXXX methods where XXXX is an interface */
+ /* therefore, we don't know the order of visiting; but we know */
+ /* these methods are called before the visitYYYY methods below */
+ /***************************************************************/
+
+ /**
+ * Assures the generic preconditions of a LoadClass instance.
+ * The referenced class is loaded and pass2-verified.
+ */
+ public void visitLoadClass(LoadClass o){
+ ObjectType t = o.getLoadClassType(cpg);
+ if (t != null){// null means "no class is loaded"
+ Verifier v = VerifierFactory.getVerifier(t.getClassName());
+ VerificationResult vr = v.doPass2();
+ if (vr.getStatus() != VerificationResult.VERIFIED_OK){
+ constraintViolated((Instruction) o, "Class '"+o.getLoadClassType(cpg).getClassName()+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
+ }
+ }
+ }
+
+ /**
+ * Ensures the general preconditions of a StackConsumer instance.
+ */
+ public void visitStackConsumer(StackConsumer o){
+ _visitStackAccessor((Instruction) o);
+ }
+
+ /**
+ * Ensures the general preconditions of a StackProducer instance.
+ */
+ public void visitStackProducer(StackProducer o){
+ _visitStackAccessor((Instruction) o);
+ }
+
+
+ /***************************************************************/
+ /* "generic" visitYYYY methods where YYYY is a superclass. */
+ /* therefore, we know the order of visiting; we know */
+ /* these methods are called after the visitXXXX methods above. */
+ /***************************************************************/
+ /**
+ * Ensures the general preconditions of a CPInstruction instance.
+ */
+ public void visitCPInstruction(CPInstruction o){
+ int idx = o.getIndex();
+ if ((idx < 0) || (idx >= cpg.getSize())){
+ throw new AssertionViolatedException("Huh?! Constant pool index of instruction '"+o+"' illegal? Pass 3a should have checked this!");
+ }
+ }
+
+ /**
+ * Ensures the general preconditions of a FieldInstruction instance.
+ */
+ public void visitFieldInstruction(FieldInstruction o){
+ // visitLoadClass(o) has been called before: Every FieldOrMethod
+ // implements LoadClass.
+ // visitCPInstruction(o) has been called before.
+ // A FieldInstruction may be: GETFIELD, GETSTATIC, PUTFIELD, PUTSTATIC
+ Constant c = cpg.getConstant(o.getIndex());
+ if (!(c instanceof ConstantFieldref)){
+ constraintViolated(o, "Index '"+o.getIndex()+"' should refer to a CONSTANT_Fieldref_info structure, but refers to '"+c+"'.");
+ }
+ // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).
+ Type t = o.getType(cpg);
+ if (t instanceof ObjectType){
+ String name = ((ObjectType)t).getClassName();
+ Verifier v = VerifierFactory.getVerifier( name );
+ VerificationResult vr = v.doPass2();
+ if (vr.getStatus() != VerificationResult.VERIFIED_OK){
+ constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
+ }
+ }
+ }
+
+ /**
+ * Ensures the general preconditions of an InvokeInstruction instance.
+ */
+ public void visitInvokeInstruction(InvokeInstruction o){
+ // visitLoadClass(o) has been called before: Every FieldOrMethod
+ // implements LoadClass.
+ // visitCPInstruction(o) has been called before.
+//TODO
+ }
+
+ /**
+ * Ensures the general preconditions of a StackInstruction instance.
+ */
+ public void visitStackInstruction(StackInstruction o){
+ _visitStackAccessor(o);
+ }
+
+ /**
+ * Assures the generic preconditions of a LocalVariableInstruction instance.
+ * That is, the index of the local variable must be valid.
+ */
+ public void visitLocalVariableInstruction(LocalVariableInstruction o){
+ if (locals().maxLocals() <= (o.getType(cpg).getSize()==1? o.getIndex() : o.getIndex()+1) ){
+ constraintViolated(o, "The 'index' is not a valid index into the local variable array.");
+ }
+ }
+
+ /**
+ * Assures the generic preconditions of a LoadInstruction instance.
+ */
+ public void visitLoadInstruction(LoadInstruction o){
+ //visitLocalVariableInstruction(o) is called before, because it is more generic.
+
+ // LOAD instructions must not read Type.UNKNOWN
+ if (locals().get(o.getIndex()) == Type.UNKNOWN){
+ constraintViolated(o, "Read-Access on local variable "+o.getIndex()+" with unknown content.");
+ }
+
+ // LOAD instructions, two-slot-values at index N must have Type.UNKNOWN
+ // as a symbol for the higher halve at index N+1
+ // [suppose some instruction put an int at N+1--- our double at N is defective]
+ if (o.getType(cpg).getSize() == 2){
+ if (locals().get(o.getIndex()+1) != Type.UNKNOWN){
+ constraintViolated(o, "Reading a two-locals value from local variables "+o.getIndex()+" and "+(o.getIndex()+1)+" where the latter one is destroyed.");
+ }
+ }
+
+ // LOAD instructions must read the correct type.
+ if (!(o instanceof ALOAD)){
+ if (locals().get(o.getIndex()) != o.getType(cpg) ){
+ constraintViolated(o, "Local Variable type and LOADing Instruction type mismatch: Local Variable: '"+locals().get(o.getIndex())+"'; Instruction type: '"+o.getType(cpg)+"'.");
+ }
+ }
+ else{ // we deal with an ALOAD
+ if (!(locals().get(o.getIndex()) instanceof ReferenceType)){
+ constraintViolated(o, "Local Variable type and LOADing Instruction type mismatch: Local Variable: '"+locals().get(o.getIndex())+"'; Instruction expects a ReferenceType.");
+ }
+ // ALOAD __IS ALLOWED__ to put uninitialized objects onto the stack!
+ //referenceTypeIsInitialized(o, (ReferenceType) (locals().get(o.getIndex())));
+ }
+
+ // LOAD instructions must have enough free stack slots.
+ if ((stack().maxStack() - stack().slotsUsed()) < o.getType(cpg).getSize()){
+ constraintViolated(o, "Not enough free stack slots to load a '"+o.getType(cpg)+"' onto the OperandStack.");
+ }
+ }
+
+ /**
+ * Assures the generic preconditions of a StoreInstruction instance.
+ */
+ public void visitStoreInstruction(StoreInstruction o){
+ //visitLocalVariableInstruction(o) is called before, because it is more generic.
+
+ if (stack().isEmpty()){ // Don't bother about 1 or 2 stack slots used. This check is implicitely done below while type checking.
+ constraintViolated(o, "Cannot STORE: Stack to read from is empty.");
+ }
+
+ if ( (!(o instanceof ASTORE)) ){
+ if (! (stack().peek() == o.getType(cpg)) ){// the other xSTORE types are singletons in BCEL.
+ constraintViolated(o, "Stack top type and STOREing Instruction type mismatch: Stack top: '"+stack().peek()+"'; Instruction type: '"+o.getType(cpg)+"'.");
+ }
+ }
+ else{ // we deal with ASTORE
+ Type stacktop = stack().peek();
+ if ( (!(stacktop instanceof ReferenceType)) && (!(stacktop instanceof ReturnaddressType)) ){
+ constraintViolated(o, "Stack top type and STOREing Instruction type mismatch: Stack top: '"+stack().peek()+"'; Instruction expects a ReferenceType or a ReturnadressType.");
+ }
+ if (stacktop instanceof ReferenceType){
+ referenceTypeIsInitialized(o, (ReferenceType) stacktop);
+ }
+ }
+ }
+
+ /**
+ * Assures the generic preconditions of a ReturnInstruction instance.
+ */
+ public void visitReturnInstruction(ReturnInstruction o){
+ if (o instanceof RETURN){
+ return;
+ }
+ if (o instanceof ARETURN){
+ if (stack().peek() == Type.NULL){
+ return;
+ }
+ else{
+ if (! (stack().peek() instanceof ReferenceType)){
+ constraintViolated(o, "Reference type expected on top of stack, but is: '"+stack().peek()+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()));
+ ReferenceType objectref = (ReferenceType) (stack().peek());
+ // TODO: This can only be checked if using Staerk-et-al's "set of object types" instead of a
+ // "wider cast object type" created during verification.
+ //if (! (objectref.isAssignmentCompatibleWith(mg.getType())) ){
+ // constraintViolated(o, "Type on stack top which should be returned is a '"+stack().peek()+"' which is not assignment compatible with the return type of this method, '"+mg.getType()+"'.");
+ //}
+ }
+ }
+ else{
+ Type method_type = mg.getType();
+ if (method_type == Type.BOOLEAN ||
+ method_type == Type.BYTE ||
+ method_type == Type.SHORT ||
+ method_type == Type.CHAR){
+ method_type = Type.INT;
+ }
+ if (! ( method_type.equals( stack().peek() ))){
+ constraintViolated(o, "Current method has return type of '"+mg.getType()+"' expecting a '"+method_type+"' on top of the stack. But stack top is a '"+stack().peek()+"'.");
+ }
+ }
+ }
+
+ /***************************************************************/
+ /* "special"visitXXXX methods for one type of instruction each */
+ /***************************************************************/
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitAALOAD(AALOAD o){
+ Type arrayref = stack().peek(1);
+ Type index = stack().peek(0);
+
+ indexOfInt(o, index);
+ if (arrayrefOfArrayType(o, arrayref)){
+ if (! (((ArrayType) arrayref).getElementType() instanceof ReferenceType)){
+ constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a ReferenceType but to an array of "+((ArrayType) arrayref).getElementType()+".");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) (((ArrayType) arrayref).getElementType()));
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitAASTORE(AASTORE o){
+ Type arrayref = stack().peek(2);
+ Type index = stack().peek(1);
+ Type value = stack().peek(0);
+
+ indexOfInt(o, index);
+ if (!(value instanceof ReferenceType)){
+ constraintViolated(o, "The 'value' is not of a ReferenceType but of type "+value+".");
+ }else{
+ referenceTypeIsInitialized(o, (ReferenceType) value);
+ }
+ // Don't bother further with "referenceTypeIsInitialized()", there are no arrays
+ // of an uninitialized object type.
+ if (arrayrefOfArrayType(o, arrayref)){
+ if (! (((ArrayType) arrayref).getElementType() instanceof ReferenceType)){
+ constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a ReferenceType but to an array of "+((ArrayType) arrayref).getElementType()+".");
+ }
+ if (! ((ReferenceType)value).isAssignmentCompatibleWith((ReferenceType) ((ArrayType) arrayref).getElementType())){
+ constraintViolated(o, "The type of 'value' ('"+value+"') is not assignment compatible to the components of the array 'arrayref' refers to. ('"+((ArrayType) arrayref).getElementType()+"')");
+ }
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitACONST_NULL(ACONST_NULL o){
+ // Nothing needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitALOAD(ALOAD o){
+ //visitLoadInstruction(LoadInstruction) is called before.
+
+ // Nothing else needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitANEWARRAY(ANEWARRAY o){
+ if (!stack().peek().equals(Type.INT))
+ constraintViolated(o, "The 'count' at the stack top is not of type '"+Type.INT+"' but of type '"+stack().peek()+"'.");
+ // The runtime constant pool item at that index must be a symbolic reference to a class,
+ // array, or interface type. See Pass 3a.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitARETURN(ARETURN o){
+ if (! (stack().peek() instanceof ReferenceType) ){
+ constraintViolated(o, "The 'objectref' at the stack top is not of a ReferenceType but of type '"+stack().peek()+"'.");
+ }
+ ReferenceType objectref = (ReferenceType) (stack().peek());
+ referenceTypeIsInitialized(o, objectref);
+
+ // The check below should already done via visitReturnInstruction(ReturnInstruction), see there.
+ // It cannot be done using Staerk-et-al's "set of object types" instead of a
+ // "wider cast object type", anyway.
+ //if (! objectref.isAssignmentCompatibleWith(mg.getReturnType() )){
+ // constraintViolated(o, "The 'objectref' type "+objectref+" at the stack top is not assignment compatible with the return type '"+mg.getReturnType()+"' of the method.");
+ //}
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitARRAYLENGTH(ARRAYLENGTH o){
+ Type arrayref = stack().peek(0);
+ arrayrefOfArrayType(o, arrayref);
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitASTORE(ASTORE o){
+ if (! ( (stack().peek() instanceof ReferenceType) || (stack().peek() instanceof ReturnaddressType) ) ){
+ constraintViolated(o, "The 'objectref' is not of a ReferenceType or of ReturnaddressType but of "+stack().peek()+".");
+ }
+ if (stack().peek() instanceof ReferenceType){
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitATHROW(ATHROW o){
+ // It's stated that 'objectref' must be of a ReferenceType --- but since Throwable is
+ // not derived from an ArrayType, it follows that 'objectref' must be of an ObjectType or Type.NULL.
+ if (! ((stack().peek() instanceof ObjectType) || (stack().peek().equals(Type.NULL))) ){
+ constraintViolated(o, "The 'objectref' is not of an (initialized) ObjectType but of type "+stack().peek()+".");
+ }
+
+ // NULL is a subclass of every class, so to speak.
+ if (stack().peek().equals(Type.NULL)) return;
+
+ ObjectType exc = (ObjectType) (stack().peek());
+ ObjectType throwable = (ObjectType) (Type.getType("Ljava/lang/Throwable;"));
+ if ( (! (exc.subclassOf(throwable)) ) && (! (exc.equals(throwable))) ){
+ constraintViolated(o, "The 'objectref' is not of class Throwable or of a subclass of Throwable, but of '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitBALOAD(BALOAD o){
+ Type arrayref = stack().peek(1);
+ Type index = stack().peek(0);
+ indexOfInt(o, index);
+ if (arrayrefOfArrayType(o, arrayref)){
+ if (! ( (((ArrayType) arrayref).getElementType().equals(Type.BOOLEAN)) ||
+ (((ArrayType) arrayref).getElementType().equals(Type.BYTE)) ) ){
+ constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a Type.BYTE or Type.BOOLEAN but to an array of '"+((ArrayType) arrayref).getElementType()+"'.");
+ }
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitBASTORE(BASTORE o){
+ Type arrayref = stack().peek(2);
+ Type index = stack().peek(1);
+ Type value = stack().peek(0);
+
+ indexOfInt(o, index);
+ valueOfInt(o, index);
+ if (arrayrefOfArrayType(o, arrayref)){
+ if (! ( (((ArrayType) arrayref).getElementType().equals(Type.BOOLEAN)) ||
+ (((ArrayType) arrayref).getElementType().equals(Type.BYTE)) ) )
+ constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a Type.BYTE or Type.BOOLEAN but to an array of '"+((ArrayType) arrayref).getElementType()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitBIPUSH(BIPUSH o){
+ // Nothing to do...
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitBREAKPOINT(BREAKPOINT o){
+ throw new AssertionViolatedException("In this JustIce verification pass there should not occur an illegal instruction such as BREAKPOINT.");
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitCALOAD(CALOAD o){
+ Type arrayref = stack().peek(1);
+ Type index = stack().peek(0);
+
+ indexOfInt(o, index);
+ arrayrefOfArrayType(o, arrayref);
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitCASTORE(CASTORE o){
+ Type arrayref = stack().peek(2);
+ Type index = stack().peek(1);
+ Type value = stack().peek(0);
+
+ indexOfInt(o, index);
+ valueOfInt(o, index);
+ if (arrayrefOfArrayType(o, arrayref)){
+ if (! ((ArrayType) arrayref).getElementType().equals(Type.CHAR) ){
+ constraintViolated(o, "The 'arrayref' does not refer to an array with elements of type char but to an array of type "+((ArrayType) arrayref).getElementType()+".");
+ }
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitCHECKCAST(CHECKCAST o){
+ // The objectref must be of type reference.
+ Type objectref = stack().peek(0);
+ if (!(objectref instanceof ReferenceType)){
+ constraintViolated(o, "The 'objectref' is not of a ReferenceType but of type "+objectref+".");
+ }
+ else{
+ referenceTypeIsInitialized(o, (ReferenceType) objectref);
+ }
+ // The unsigned indexbyte1 and indexbyte2 are used to construct an index into the runtime constant pool of the
+ // current class (§3.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The runtime constant
+ // pool item at the index must be a symbolic reference to a class, array, or interface type.
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! (c instanceof ConstantClass)){
+ constraintViolated(o, "The Constant at 'index' is not a ConstantClass, but '"+c+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitD2F(D2F o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitD2I(D2I o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitD2L(D2L o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDADD(DADD o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDALOAD(DALOAD o){
+ indexOfInt(o, stack().peek());
+ if (stack().peek(1) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(1) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-top must be of type double[] but is '"+stack().peek(1)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(1))).getBasicType();
+ if (t != Type.DOUBLE){
+ constraintViolated(o, "Stack next-to-top must be of type double[] but is '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDASTORE(DASTORE o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ indexOfInt(o, stack().peek(1));
+ if (stack().peek(2) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(2) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type double[] but is '"+stack().peek(2)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(2))).getBasicType();
+ if (t != Type.DOUBLE){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type double[] but is '"+stack().peek(2)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDCMPG(DCMPG o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDCMPL(DCMPL o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDCONST(DCONST o){
+ // There's nothing to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDDIV(DDIV o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDLOAD(DLOAD o){
+ //visitLoadInstruction(LoadInstruction) is called before.
+
+ // Nothing else needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDMUL(DMUL o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDNEG(DNEG o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDREM(DREM o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDRETURN(DRETURN o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDSTORE(DSTORE o){
+ //visitStoreInstruction(StoreInstruction) is called before.
+
+ // Nothing else needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDSUB(DSUB o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDUP(DUP o){
+ if (stack().peek().getSize() != 1){
+ constraintViolated(o, "Won't DUP type on stack top '"+stack().peek()+"' because it must occupy exactly one slot, not '"+stack().peek().getSize()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDUP_X1(DUP_X1 o){
+ if (stack().peek().getSize() != 1){
+ constraintViolated(o, "Type on stack top '"+stack().peek()+"' should occupy exactly one slot, not '"+stack().peek().getSize()+"'.");
+ }
+ if (stack().peek(1).getSize() != 1){
+ constraintViolated(o, "Type on stack next-to-top '"+stack().peek(1)+"' should occupy exactly one slot, not '"+stack().peek(1).getSize()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDUP_X2(DUP_X2 o){
+ if (stack().peek().getSize() != 1){
+ constraintViolated(o, "Stack top type must be of size 1, but is '"+stack().peek()+"' of size '"+stack().peek().getSize()+"'.");
+ }
+ if (stack().peek(1).getSize() == 2){
+ return; // Form 2, okay.
+ }
+ else{ //stack().peek(1).getSize == 1.
+ if (stack().peek(2).getSize() != 1){
+ 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: '"+stack().peek(2)+"' of size '"+stack().peek(2).getSize()+"'.");
+ }
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDUP2(DUP2 o){
+ if (stack().peek().getSize() == 2){
+ return; // Form 2, okay.
+ }
+ else{ //stack().peek().getSize() == 1.
+ if (stack().peek(1).getSize() != 1){
+ 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 '"+stack().peek(1).getSize()+"'.");
+ }
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDUP2_X1(DUP2_X1 o){
+ if (stack().peek().getSize() == 2){
+ if (stack().peek(1).getSize() != 1){
+ 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 '"+stack().peek(1).getSize()+"'.");
+ }
+ else{
+ return; // Form 2
+ }
+ }
+ else{ // stack top is of size 1
+ if ( stack().peek(1).getSize() != 1 ){
+ 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 '"+stack().peek(1).getSize()+"'.");
+ }
+ if ( stack().peek(2).getSize() != 1 ){
+ 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)+"' of size '"+stack().peek(2).getSize()+"'.");
+ }
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDUP2_X2(DUP2_X2 o){
+
+ if (stack().peek(0).getSize() == 2){
+ if (stack().peek(1).getSize() == 2){
+ return; // Form 4
+ }
+ else{// stack top size is 2, next-to-top's size is 1
+ if ( stack().peek(2).getSize() != 1 ){
+ constraintViolated(o, "If stack top's size is 2 and stack-next-to-top's size is 1, 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()+"'.");
+ }
+ else{
+ return; // Form 2
+ }
+ }
+ }
+ else{// stack top is of size 1
+ if (stack().peek(1).getSize() == 1){
+ if ( stack().peek(2).getSize() == 2 ){
+ return; // Form 3
+ }
+ else{
+ if ( stack().peek(3).getSize() == 1){
+ return; // Form 1
+ }
+ }
+ }
+ }
+ constraintViolated(o, "The operand sizes on the stack do not match any of the four forms of usage of this instruction.");
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitF2D(F2D o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitF2I(F2I o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitF2L(F2L o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFADD(FADD o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.FLOAT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFALOAD(FALOAD o){
+ indexOfInt(o, stack().peek());
+ if (stack().peek(1) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(1) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-top must be of type float[] but is '"+stack().peek(1)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(1))).getBasicType();
+ if (t != Type.FLOAT){
+ constraintViolated(o, "Stack next-to-top must be of type float[] but is '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFASTORE(FASTORE o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ indexOfInt(o, stack().peek(1));
+ if (stack().peek(2) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(2) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type float[] but is '"+stack().peek(2)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(2))).getBasicType();
+ if (t != Type.FLOAT){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type float[] but is '"+stack().peek(2)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFCMPG(FCMPG o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.FLOAT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFCMPL(FCMPL o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.FLOAT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFCONST(FCONST o){
+ // nothing to do here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFDIV(FDIV o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.FLOAT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFLOAD(FLOAD o){
+ //visitLoadInstruction(LoadInstruction) is called before.
+
+ // Nothing else needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFMUL(FMUL o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.FLOAT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFNEG(FNEG o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFREM(FREM o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.FLOAT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFRETURN(FRETURN o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFSTORE(FSTORE o){
+ //visitStoreInstruction(StoreInstruction) is called before.
+
+ // Nothing else needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFSUB(FSUB o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.FLOAT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitGETFIELD(GETFIELD o){
+ Type objectref = stack().peek();
+ if (! ( (objectref instanceof ObjectType) || (objectref == Type.NULL) ) ){
+ constraintViolated(o, "Stack top should be an object reference that's not an array reference, but is '"+objectref+"'.");
+ }
+
+ String field_name = o.getFieldName(cpg);
+
+ JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
+ Field[] fields = jc.getFields();
+ Field f = null;
+ for (int i=0; i<fields.length; i++){
+ if (fields[i].getName().equals(field_name)){
+ f = fields[i];
+ break;
+ }
+ }
+ if (f == null){
+ throw new AssertionViolatedException("Field not found?!?");
+ }
+
+ if (f.isProtected()){
+ ObjectType classtype = o.getClassType(cpg);
+ ObjectType curr = new ObjectType(mg.getClassName());
+
+ if ( classtype.equals(curr) ||
+ curr.subclassOf(classtype) ){
+ Type t = stack().peek();
+ if (t == Type.NULL){
+ return;
+ }
+ if (! (t instanceof ObjectType) ){
+ constraintViolated(o, "The 'objectref' must refer to an object that's not an array. Found instead: '"+t+"'.");
+ }
+ ObjectType objreftype = (ObjectType) t;
+ if (! ( objreftype.equals(curr) ||
+ objreftype.subclassOf(curr) ) ){
+ //TODO: One day move to Staerk-et-al's "Set of object types" instead of "wider" object types
+ // created during the verification.
+ // "Wider" object types don't allow us to check for things like that below.
+ //constraintViolated(o, "The referenced field has the ACC_PROTECTED modifier, and it's a member of the current class or a superclass of the current class. However, the referenced object type '"+stack().peek()+"' is not the current class or a subclass of the current class.");
+ }
+ }
+ }
+
+ // TODO: Could go into Pass 3a.
+ if (f.isStatic()){
+ constraintViolated(o, "Referenced field '"+f+"' is static which it shouldn't be.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitGETSTATIC(GETSTATIC o){
+ // Field must be static: see Pass 3a.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitGOTO(GOTO o){
+ // nothing to do here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitGOTO_W(GOTO_W o){
+ // nothing to do here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitI2B(I2B o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitI2C(I2C o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitI2D(I2D o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitI2F(I2F o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitI2L(I2L o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitI2S(I2S o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIADD(IADD o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIALOAD(IALOAD o){
+ indexOfInt(o, stack().peek());
+ if (stack().peek(1) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(1) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-top must be of type int[] but is '"+stack().peek(1)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(1))).getBasicType();
+ if (t != Type.INT){
+ constraintViolated(o, "Stack next-to-top must be of type int[] but is '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIAND(IAND o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIASTORE(IASTORE o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ indexOfInt(o, stack().peek(1));
+ if (stack().peek(2) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(2) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type int[] but is '"+stack().peek(2)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(2))).getBasicType();
+ if (t != Type.INT){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type int[] but is '"+stack().peek(2)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitICONST(ICONST o){
+ //nothing to do here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIDIV(IDIV o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIF_ACMPEQ(IF_ACMPEQ o){
+ if (!(stack().peek() instanceof ReferenceType)){
+ constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '"+stack().peek()+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
+
+ if (!(stack().peek(1) instanceof ReferenceType)){
+ constraintViolated(o, "The value at the stack next-to-top is not of a ReferenceType, but of type '"+stack().peek(1)+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek(1)) );
+
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIF_ACMPNE(IF_ACMPNE o){
+ if (!(stack().peek() instanceof ReferenceType)){
+ constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '"+stack().peek()+"'.");
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
+ }
+ if (!(stack().peek(1) instanceof ReferenceType)){
+ constraintViolated(o, "The value at the stack next-to-top is not of a ReferenceType, but of type '"+stack().peek(1)+"'.");
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek(1)) );
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIF_ICMPEQ(IF_ICMPEQ o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIF_ICMPGE(IF_ICMPGE o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIF_ICMPGT(IF_ICMPGT o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIF_ICMPLE(IF_ICMPLE o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIF_ICMPLT(IF_ICMPLT o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIF_ICMPNE(IF_ICMPNE o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIFEQ(IFEQ o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIFGE(IFGE o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIFGT(IFGT o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIFLE(IFLE o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIFLT(IFLT o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIFNE(IFNE o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIFNONNULL(IFNONNULL o){
+ if (!(stack().peek() instanceof ReferenceType)){
+ constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '"+stack().peek()+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIFNULL(IFNULL o){
+ if (!(stack().peek() instanceof ReferenceType)){
+ constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '"+stack().peek()+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIINC(IINC o){
+ // Mhhh. In BCEL, at this time "IINC" is not a LocalVariableInstruction.
+ if (locals().maxLocals() <= (o.getType(cpg).getSize()==1? o.getIndex() : o.getIndex()+1) ){
+ constraintViolated(o, "The 'index' is not a valid index into the local variable array.");
+ }
+
+ indexOfInt(o, locals().get(o.getIndex()));
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitILOAD(ILOAD o){
+ // All done by visitLocalVariableInstruction(), visitLoadInstruction()
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIMPDEP1(IMPDEP1 o){
+ throw new AssertionViolatedException("In this JustIce verification pass there should not occur an illegal instruction such as IMPDEP1.");
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIMPDEP2(IMPDEP2 o){
+ throw new AssertionViolatedException("In this JustIce verification pass there should not occur an illegal instruction such as IMPDEP2.");
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIMUL(IMUL o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitINEG(INEG o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitINSTANCEOF(INSTANCEOF o){
+ // The objectref must be of type reference.
+ Type objectref = stack().peek(0);
+ if (!(objectref instanceof ReferenceType)){
+ constraintViolated(o, "The 'objectref' is not of a ReferenceType but of type "+objectref+".");
+ }
+ else{
+ referenceTypeIsInitialized(o, (ReferenceType) objectref);
+ }
+ // The unsigned indexbyte1 and indexbyte2 are used to construct an index into the runtime constant pool of the
+ // current class (§3.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The runtime constant
+ // pool item at the index must be a symbolic reference to a class, array, or interface type.
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! (c instanceof ConstantClass)){
+ constraintViolated(o, "The Constant at 'index' is not a ConstantClass, but '"+c+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitINVOKEINTERFACE(INVOKEINTERFACE o){
+ // Method is not native, otherwise pass 3 would not happen.
+
+ int count = o.getCount();
+ if (count == 0){
+ constraintViolated(o, "The 'count' argument must not be 0.");
+ }
+ // It is a ConstantInterfaceMethodref, Pass 3a made it sure.
+ ConstantInterfaceMethodref cimr = (ConstantInterfaceMethodref) (cpg.getConstant(o.getIndex()));
+
+ // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).
+
+ Type t = o.getType(cpg);
+ if (t instanceof ObjectType){
+ String name = ((ObjectType)t).getClassName();
+ Verifier v = VerifierFactory.getVerifier( name );
+ VerificationResult vr = v.doPass2();
+ if (vr.getStatus() != VerificationResult.VERIFIED_OK){
+ constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
+ }
+ }
+
+
+ Type[] argtypes = o.getArgumentTypes(cpg);
+ int nargs = argtypes.length;
+
+ for (int i=nargs-1; i>=0; i--){
+ Type fromStack = stack().peek( (nargs-1) - i ); // 0 to nargs-1
+ Type fromDesc = argtypes[i];
+ if (fromDesc == Type.BOOLEAN ||
+ fromDesc == Type.BYTE ||
+ fromDesc == Type.CHAR ||
+ fromDesc == Type.SHORT){
+ fromDesc = Type.INT;
+ }
+ if (! fromStack.equals(fromDesc)){
+ if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType){
+ ReferenceType rFromStack = (ReferenceType) fromStack;
+ ReferenceType rFromDesc = (ReferenceType) fromDesc;
+ // TODO: This can only be checked when using Staerk-et-al's "set of object types"
+ // instead of a "wider cast object type" created during verification.
+ //if ( ! rFromStack.isAssignmentCompatibleWith(rFromDesc) ){
+ // constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack (which is not assignment compatible).");
+ //}
+ }
+ else{
+ constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack.");
+ }
+ }
+ }
+
+ Type objref = stack().peek(nargs);
+ if (objref == Type.NULL){
+ return;
+ }
+ if (! (objref instanceof ReferenceType) ){
+ constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '"+objref+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) objref);
+ if (!(objref instanceof ObjectType)){
+ if (!(objref instanceof ArrayType)){
+ constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '"+objref+"'."); // could be a ReturnaddressType
+ }
+ else{
+ objref = GENERIC_ARRAY;
+ }
+ }
+
+ String objref_classname = ((ObjectType) objref).getClassName();
+
+ String theInterface = o.getClassName(cpg);
+
+ // TODO: This can only be checked if we're using Staerk-et-al's "set of object types"
+ // instead of "wider cast object types" generated during verification.
+ //if ( ! Repository.implementationOf(objref_classname, theInterface) ){
+ // constraintViolated(o, "The 'objref' item '"+objref+"' does not implement '"+theInterface+"' as expected.");
+ //}
+
+ int counted_count = 1; // 1 for the objectref
+ for (int i=0; i<nargs; i++){
+ counted_count += argtypes[i].getSize();
+ }
+ if (count != counted_count){
+ constraintViolated(o, "The 'count' argument should probably read '"+counted_count+"' but is '"+count+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitINVOKESPECIAL(INVOKESPECIAL o){
+ // Don't init an object twice.
+ if ( (o.getMethodName(cpg).equals(Constants.CONSTRUCTOR_NAME)) && (!(stack().peek(o.getArgumentTypes(cpg).length) instanceof UninitializedObjectType)) ){
+ constraintViolated(o, "Possibly initializing object twice. A valid instruction sequence must not have an uninitialized object on the operand stack or in a local variable during a backwards branch, or in a local variable in code protected by an exception handler. Please see The Java Virtual Machine Specification, Second Edition, 4.9.4 (pages 147 and 148) for details.");
+ }
+
+ // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).
+
+ Type t = o.getType(cpg);
+ if (t instanceof ObjectType){
+ String name = ((ObjectType)t).getClassName();
+ Verifier v = VerifierFactory.getVerifier( name );
+ VerificationResult vr = v.doPass2();
+ if (vr.getStatus() != VerificationResult.VERIFIED_OK){
+ constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
+ }
+ }
+
+
+ Type[] argtypes = o.getArgumentTypes(cpg);
+ int nargs = argtypes.length;
+
+ for (int i=nargs-1; i>=0; i--){
+ Type fromStack = stack().peek( (nargs-1) - i ); // 0 to nargs-1
+ Type fromDesc = argtypes[i];
+ if (fromDesc == Type.BOOLEAN ||
+ fromDesc == Type.BYTE ||
+ fromDesc == Type.CHAR ||
+ fromDesc == Type.SHORT){
+ fromDesc = Type.INT;
+ }
+ if (! fromStack.equals(fromDesc)){
+ if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType){
+ ReferenceType rFromStack = (ReferenceType) fromStack;
+ ReferenceType rFromDesc = (ReferenceType) fromDesc;
+ // TODO: This can only be checked using Staerk-et-al's "set of object types", not
+ // using a "wider cast object type".
+ //if ( ! rFromStack.isAssignmentCompatibleWith(rFromDesc) ){
+ // constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack (which is not assignment compatible).");
+ //}
+ }
+ else{
+ constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack.");
+ }
+ }
+ }
+
+ Type objref = stack().peek(nargs);
+ if (objref == Type.NULL){
+ return;
+ }
+ if (! (objref instanceof ReferenceType) ){
+ constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '"+objref+"'.");
+ }
+ String objref_classname = null;
+ if ( !(o.getMethodName(cpg).equals(Constants.CONSTRUCTOR_NAME))){
+ referenceTypeIsInitialized(o, (ReferenceType) objref);
+ if (!(objref instanceof ObjectType)){
+ if (!(objref instanceof ArrayType)){
+ constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '"+objref+"'."); // could be a ReturnaddressType
+ }
+ else{
+ objref = GENERIC_ARRAY;
+ }
+ }
+
+ objref_classname = ((ObjectType) objref).getClassName();
+ }
+ else{
+ if (!(objref instanceof UninitializedObjectType)){
+ constraintViolated(o, "Expecting an UninitializedObjectType as 'objectref' on the stack, not a '"+objref+"'. Otherwise, you couldn't invoke a method since an array has no methods (not to speak of a return address).");
+ }
+ objref_classname = ((UninitializedObjectType) objref).getInitialized().getClassName();
+ }
+
+
+ String theClass = o.getClassName(cpg);
+ if ( ! Repository.instanceOf(objref_classname, theClass) ){
+ constraintViolated(o, "The 'objref' item '"+objref+"' does not implement '"+theClass+"' as expected.");
+ }
+
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitINVOKESTATIC(INVOKESTATIC o){
+ // Method is not native, otherwise pass 3 would not happen.
+
+ Type t = o.getType(cpg);
+ if (t instanceof ObjectType){
+ String name = ((ObjectType)t).getClassName();
+ Verifier v = VerifierFactory.getVerifier( name );
+ VerificationResult vr = v.doPass2();
+ if (vr.getStatus() != VerificationResult.VERIFIED_OK){
+ constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
+ }
+ }
+
+ Type[] argtypes = o.getArgumentTypes(cpg);
+ int nargs = argtypes.length;
+
+ for (int i=nargs-1; i>=0; i--){
+ Type fromStack = stack().peek( (nargs-1) - i ); // 0 to nargs-1
+ Type fromDesc = argtypes[i];
+ if (fromDesc == Type.BOOLEAN ||
+ fromDesc == Type.BYTE ||
+ fromDesc == Type.CHAR ||
+ fromDesc == Type.SHORT){
+ fromDesc = Type.INT;
+ }
+ if (! fromStack.equals(fromDesc)){
+ if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType){
+ ReferenceType rFromStack = (ReferenceType) fromStack;
+ ReferenceType rFromDesc = (ReferenceType) fromDesc;
+ // TODO: This check can only be done using Staerk-et-al's "set of object types"
+ // instead of a "wider cast object type" created during verification.
+ //if ( ! rFromStack.isAssignmentCompatibleWith(rFromDesc) ){
+ // constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack (which is not assignment compatible).");
+ //}
+ }
+ else{
+ constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack.");
+ }
+ }
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitINVOKEVIRTUAL(INVOKEVIRTUAL o){
+ // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).
+
+ Type t = o.getType(cpg);
+ if (t instanceof ObjectType){
+ String name = ((ObjectType)t).getClassName();
+ Verifier v = VerifierFactory.getVerifier( name );
+ VerificationResult vr = v.doPass2();
+ if (vr.getStatus() != VerificationResult.VERIFIED_OK){
+ constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
+ }
+ }
+
+
+ Type[] argtypes = o.getArgumentTypes(cpg);
+ int nargs = argtypes.length;
+
+ for (int i=nargs-1; i>=0; i--){
+ Type fromStack = stack().peek( (nargs-1) - i ); // 0 to nargs-1
+ Type fromDesc = argtypes[i];
+ if (fromDesc == Type.BOOLEAN ||
+ fromDesc == Type.BYTE ||
+ fromDesc == Type.CHAR ||
+ fromDesc == Type.SHORT){
+ fromDesc = Type.INT;
+ }
+ if (! fromStack.equals(fromDesc)){
+ if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType){
+ ReferenceType rFromStack = (ReferenceType) fromStack;
+ ReferenceType rFromDesc = (ReferenceType) fromDesc;
+ // TODO: This can only be checked when using Staerk-et-al's "set of object types" instead
+ // of a single "wider cast object type" created during verification.
+ //if ( ! rFromStack.isAssignmentCompatibleWith(rFromDesc) ){
+ // constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack (which is not assignment compatible).");
+ //}
+ }
+ else{
+ constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack.");
+ }
+ }
+ }
+
+ Type objref = stack().peek(nargs);
+ if (objref == Type.NULL){
+ return;
+ }
+ if (! (objref instanceof ReferenceType) ){
+ constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '"+objref+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) objref);
+ if (!(objref instanceof ObjectType)){
+ if (!(objref instanceof ArrayType)){
+ constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '"+objref+"'."); // could be a ReturnaddressType
+ }
+ else{
+ objref = GENERIC_ARRAY;
+ }
+ }
+
+ String objref_classname = ((ObjectType) objref).getClassName();
+
+ String theClass = o.getClassName(cpg);
+
+ if ( ! Repository.instanceOf(objref_classname, theClass) ){
+ constraintViolated(o, "The 'objref' item '"+objref+"' does not implement '"+theClass+"' as expected.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIOR(IOR o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIREM(IREM o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIRETURN(IRETURN o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitISHL(ISHL o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitISHR(ISHR o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitISTORE(ISTORE o){
+ //visitStoreInstruction(StoreInstruction) is called before.
+
+ // Nothing else needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitISUB(ISUB o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIUSHR(IUSHR o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIXOR(IXOR o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitJSR(JSR o){
+ // nothing to do here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitJSR_W(JSR_W o){
+ // nothing to do here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitL2D(L2D o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitL2F(L2F o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitL2I(L2I o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLADD(LADD o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLALOAD(LALOAD o){
+ indexOfInt(o, stack().peek());
+ if (stack().peek(1) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(1) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-top must be of type long[] but is '"+stack().peek(1)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(1))).getBasicType();
+ if (t != Type.LONG){
+ constraintViolated(o, "Stack next-to-top must be of type long[] but is '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLAND(LAND o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLASTORE(LASTORE o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ indexOfInt(o, stack().peek(1));
+ if (stack().peek(2) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(2) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type long[] but is '"+stack().peek(2)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(2))).getBasicType();
+ if (t != Type.LONG){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type long[] but is '"+stack().peek(2)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLCMP(LCMP o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLCONST(LCONST o){
+ // Nothing to do here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLDC(LDC o){
+ // visitCPInstruction is called first.
+
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! ( ( c instanceof ConstantInteger) ||
+ ( c instanceof ConstantFloat ) ||
+ ( c instanceof ConstantString ) ) ){
+ constraintViolated(o, "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float or a CONSTANT_String, but is '"+c+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLDC_W(LDC_W o){
+ // visitCPInstruction is called first.
+
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! ( ( c instanceof ConstantInteger) ||
+ ( c instanceof ConstantFloat ) ||
+ ( c instanceof ConstantString ) ) ){
+ constraintViolated(o, "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float or a CONSTANT_String, but is '"+c+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLDC2_W(LDC2_W o){
+ // visitCPInstruction is called first.
+
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! ( ( c instanceof ConstantLong) ||
+ ( c instanceof ConstantDouble ) ) ){
+ constraintViolated(o, "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float or a CONSTANT_String, but is '"+c+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLDIV(LDIV o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLLOAD(LLOAD o){
+ //visitLoadInstruction(LoadInstruction) is called before.
+
+ // Nothing else needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLMUL(LMUL o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLNEG(LNEG o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLOOKUPSWITCH(LOOKUPSWITCH o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ // See also pass 3a.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLOR(LOR o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLREM(LREM o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLRETURN(LRETURN o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLSHL(LSHL o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLSHR(LSHR o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLSTORE(LSTORE o){
+ //visitStoreInstruction(StoreInstruction) is called before.
+
+ // Nothing else needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLSUB(LSUB o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLUSHR(LUSHR o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLXOR(LXOR o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitMONITORENTER(MONITORENTER o){
+ if (! ((stack().peek()) instanceof ReferenceType)){
+ constraintViolated(o, "The stack top should be of a ReferenceType, but is '"+stack().peek()+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitMONITOREXIT(MONITOREXIT o){
+ if (! ((stack().peek()) instanceof ReferenceType)){
+ constraintViolated(o, "The stack top should be of a ReferenceType, but is '"+stack().peek()+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitMULTIANEWARRAY(MULTIANEWARRAY o){
+ int dimensions = o.getDimensions();
+ // Dimensions argument is okay: see Pass 3a.
+ for (int i=0; i<dimensions; i++){
+ if (stack().peek(i) != Type.INT){
+ constraintViolated(o, "The '"+dimensions+"' upper stack types should be 'int' but aren't.");
+ }
+ }
+ // The runtime constant pool item at that index must be a symbolic reference to a class,
+ // array, or interface type. See Pass 3a.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitNEW(NEW o){
+ //visitCPInstruction(CPInstruction) has been called before.
+ //visitLoadClass(LoadClass) has been called before.
+
+ Type t = o.getType(cpg);
+ if (! (t instanceof ReferenceType)){
+ throw new AssertionViolatedException("NEW.getType() returning a non-reference type?!");
+ }
+ if (! (t instanceof ObjectType)){
+ constraintViolated(o, "Expecting a class type (ObjectType) to work on. Found: '"+t+"'.");
+ }
+ ObjectType obj = (ObjectType) t;
+
+ //e.g.: Don't instantiate interfaces
+ if (! obj.referencesClass()){
+ constraintViolated(o, "Expecting a class type (ObjectType) to work on. Found: '"+obj+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitNEWARRAY(NEWARRAY o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitNOP(NOP o){
+ // nothing is to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitPOP(POP o){
+ if (stack().peek().getSize() != 1){
+ constraintViolated(o, "Stack top size should be 1 but stack top is '"+stack().peek()+"' of size '"+stack().peek().getSize()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitPOP2(POP2 o){
+ if (stack().peek().getSize() != 2){
+ constraintViolated(o, "Stack top size should be 2 but stack top is '"+stack().peek()+"' of size '"+stack().peek().getSize()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitPUTFIELD(PUTFIELD o){
+
+ Type objectref = stack().peek(1);
+ if (! ( (objectref instanceof ObjectType) || (objectref == Type.NULL) ) ){
+ constraintViolated(o, "Stack next-to-top should be an object reference that's not an array reference, but is '"+objectref+"'.");
+ }
+
+ String field_name = o.getFieldName(cpg);
+
+ JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
+ Field[] fields = jc.getFields();
+ Field f = null;
+ for (int i=0; i<fields.length; i++){
+ if (fields[i].getName().equals(field_name)){
+ f = fields[i];
+ break;
+ }
+ }
+ if (f == null){
+ throw new AssertionViolatedException("Field not found?!?");
+ }
+
+ Type value = stack().peek();
+ Type t = Type.getType(f.getSignature());
+ Type shouldbe = t;
+ if (shouldbe == Type.BOOLEAN ||
+ shouldbe == Type.BYTE ||
+ shouldbe == Type.CHAR ||
+ shouldbe == Type.SHORT){
+ shouldbe = Type.INT;
+ }
+ if (t instanceof ReferenceType){
+ ReferenceType rvalue = null;
+ if (value instanceof ReferenceType){
+ rvalue = (ReferenceType) value;
+ referenceTypeIsInitialized(o, rvalue);
+ }
+ else{
+ constraintViolated(o, "The stack top type '"+value+"' is not of a reference type as expected.");
+ }
+ // TODO: This can only be checked using Staerk-et-al's "set-of-object types", not
+ // using "wider cast object types" created during verification.
+ //if (!(rvalue.isAssignmentCompatibleWith(shouldbe))){
+ // constraintViolated(o, "The stack top type '"+value+"' is not assignment compatible with '"+shouldbe+"'.");
+ //}
+ }
+ else{
+ if (shouldbe != value){
+ constraintViolated(o, "The stack top type '"+value+"' is not of type '"+shouldbe+"' as expected.");
+ }
+ }
+
+ if (f.isProtected()){
+ ObjectType classtype = o.getClassType(cpg);
+ ObjectType curr = new ObjectType(mg.getClassName());
+
+ if ( classtype.equals(curr) ||
+ curr.subclassOf(classtype) ){
+ Type tp = stack().peek(1);
+ if (tp == Type.NULL){
+ return;
+ }
+ if (! (tp instanceof ObjectType) ){
+ constraintViolated(o, "The 'objectref' must refer to an object that's not an array. Found instead: '"+tp+"'.");
+ }
+ ObjectType objreftype = (ObjectType) tp;
+ if (! ( objreftype.equals(curr) ||
+ objreftype.subclassOf(curr) ) ){
+ constraintViolated(o, "The referenced field has the ACC_PROTECTED modifier, and it's a member of the current class or a superclass of the current class. However, the referenced object type '"+stack().peek()+"' is not the current class or a subclass of the current class.");
+ }
+ }
+ }
+
+ // TODO: Could go into Pass 3a.
+ if (f.isStatic()){
+ constraintViolated(o, "Referenced field '"+f+"' is static which it shouldn't be.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitPUTSTATIC(PUTSTATIC o){
+ String field_name = o.getFieldName(cpg);
+ JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
+ Field[] fields = jc.getFields();
+ Field f = null;
+ for (int i=0; i<fields.length; i++){
+ if (fields[i].getName().equals(field_name)){
+ f = fields[i];
+ break;
+ }
+ }
+ if (f == null){
+ throw new AssertionViolatedException("Field not found?!?");
+ }
+ Type value = stack().peek();
+ Type t = Type.getType(f.getSignature());
+ Type shouldbe = t;
+ if (shouldbe == Type.BOOLEAN ||
+ shouldbe == Type.BYTE ||
+ shouldbe == Type.CHAR ||
+ shouldbe == Type.SHORT){
+ shouldbe = Type.INT;
+ }
+ if (t instanceof ReferenceType){
+ ReferenceType rvalue = null;
+ if (value instanceof ReferenceType){
+ rvalue = (ReferenceType) value;
+ referenceTypeIsInitialized(o, rvalue);
+ }
+ else{
+ constraintViolated(o, "The stack top type '"+value+"' is not of a reference type as expected.");
+ }
+ if (!(rvalue.isAssignmentCompatibleWith(shouldbe))){
+ constraintViolated(o, "The stack top type '"+value+"' is not assignment compatible with '"+shouldbe+"'.");
+ }
+ }
+ else{
+ if (shouldbe != value){
+ constraintViolated(o, "The stack top type '"+value+"' is not of type '"+shouldbe+"' as expected.");
+ }
+ }
+ // TODO: Interface fields may be assigned to only once. (Hard to implement in
+ // JustIce's execution model). This may only happen in <clinit>, see Pass 3a.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitRET(RET o){
+ if (! (locals().get(o.getIndex()) instanceof ReturnaddressType)){
+ constraintViolated(o, "Expecting a ReturnaddressType in local variable "+o.getIndex()+".");
+ }
+ if (locals().get(o.getIndex()) == ReturnaddressType.NO_TARGET){
+ throw new AssertionViolatedException("Oops: RET expecting a target!");
+ }
+ // Other constraints such as non-allowed overlapping subroutines are enforced
+ // while building the Subroutines data structure.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitRETURN(RETURN o){
+ if (mg.getName().equals(Constants.CONSTRUCTOR_NAME)){// If we leave an <init> method
+ if ((frame._this != null) && (!(mg.getClassName().equals(Type.OBJECT.getClassName()))) ) {
+ constraintViolated(o, "Leaving a constructor that itself did not call a constructor.");
+ }
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitSALOAD(SALOAD o){
+ indexOfInt(o, stack().peek());
+ if (stack().peek(1) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(1) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-top must be of type short[] but is '"+stack().peek(1)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(1))).getBasicType();
+ if (t != Type.SHORT){
+ constraintViolated(o, "Stack next-to-top must be of type short[] but is '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitSASTORE(SASTORE o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ indexOfInt(o, stack().peek(1));
+ if (stack().peek(2) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(2) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type short[] but is '"+stack().peek(2)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(2))).getBasicType();
+ if (t != Type.SHORT){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type short[] but is '"+stack().peek(2)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitSIPUSH(SIPUSH o){
+ // nothing to do here. Generic visitXXX() methods did the trick before.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitSWAP(SWAP o){
+ if (stack().peek().getSize() != 1){
+ constraintViolated(o, "The value at the stack top is not of size '1', but of size '"+stack().peek().getSize()+"'.");
+ }
+ if (stack().peek(1).getSize() != 1){
+ constraintViolated(o, "The value at the stack next-to-top is not of size '1', but of size '"+stack().peek(1).getSize()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitTABLESWITCH(TABLESWITCH o){
+ indexOfInt(o, stack().peek());
+ // See Pass 3a.
+ }
+
+}
+
diff --git a/src/java/org/apache/bcel/verifier/structurals/InstructionContext.java b/src/java/org/apache/bcel/verifier/structurals/InstructionContext.java
new file mode 100644
index 00000000..f737bd12
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/structurals/InstructionContext.java
@@ -0,0 +1,141 @@
+package org.apache.bcel.verifier.structurals;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.generic.InstructionHandle;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * An InstructionContext offers convenient access
+ * to information like control flow successors and
+ * such.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public interface InstructionContext{
+
+ /**
+ * The getTag and setTag methods may be used for
+ * temporary flagging, such as graph colouring.
+ * Nothing in the InstructionContext object depends
+ * on the value of the tag. JustIce does not use it.
+ *
+ * @see #setTag(int tag)
+ */
+ public int getTag();
+
+ /**
+ * The getTag and setTag methods may be used for
+ * temporary flagging, such as graph colouring.
+ * Nothing in the InstructionContext object depends
+ * on the value of the tag. JustIce does not use it.
+ *
+ * @see #getTag()
+ */
+ public void setTag(int tag);
+
+ /**
+ * This method symbolically executes the Instruction
+ * held in the InstructionContext.
+ * It "merges in" the incoming execution frame situation
+ * (see The Java Virtual Machine Specification, 2nd
+ * edition, page 146).
+ * By so doing, the outgoing execution frame situation
+ * is calculated.
+ *
+ * This method is JustIce-specific and is usually of
+ * no sense for users of the ControlFlowGraph class.
+ * They should use getInstruction().accept(Visitor),
+ * possibly in conjunction with the ExecutionVisitor.
+ *
+ *
+ * @see ControlFlowGraph
+ * @see ExecutionVisitor
+ * @see #getOutFrame(ArrayList)
+ * @return true - if and only if the "outgoing" frame situation
+ * changed from the one before execute()ing.
+ */
+ boolean execute(Frame inFrame, ArrayList executionPredecessors, InstConstraintVisitor icv, ExecutionVisitor ev);
+
+ /**
+ * This method returns the outgoing execution frame situation;
+ * therefore <B>it has to be calculated by execute(Frame, ArrayList)
+ * first.</B>
+ *
+ * @see #execute(Frame, ArrayList, InstConstraintVisitor, ExecutionVisitor)
+ */
+ Frame getOutFrame(ArrayList executionPredecessors);
+
+ /**
+ * Returns the InstructionHandle this InstructionContext is wrapped around.
+ *
+ * @return The InstructionHandle this InstructionContext is wrapped around.
+ */
+ InstructionHandle getInstruction();
+
+ /**
+ * Returns the usual control flow successors.
+ * @see #getExceptionHandlers()
+ */
+ InstructionContext[] getSuccessors();
+
+ /**
+ * Returns the exception handlers that protect this instruction.
+ * They are special control flow successors.
+ */
+ ExceptionHandler[] getExceptionHandlers();
+}
diff --git a/src/java/org/apache/bcel/verifier/structurals/LocalVariables.java b/src/java/org/apache/bcel/verifier/structurals/LocalVariables.java
new file mode 100644
index 00000000..6dad821b
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/structurals/LocalVariables.java
@@ -0,0 +1,229 @@
+package org.apache.bcel.verifier.structurals;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.generic.Type;
+import org.apache.bcel.generic.ReferenceType;
+import org.apache.bcel.verifier.exc.*;
+
+/**
+ * This class implements an array of local variables used for symbolic JVM
+ * simulation.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class LocalVariables{
+ /** The Type[] containing the local variable slots. */
+ private Type[] locals;
+
+ /**
+ * Creates a new LocalVariables object.
+ */
+ public LocalVariables(int maxLocals){
+ locals = new Type[maxLocals];
+ for (int i=0; i<maxLocals; i++){
+ locals[i] = Type.UNKNOWN;
+ }
+ }
+
+ /**
+ * Returns a deep copy of this object; i.e. the clone
+ * operates on a new local variable array.
+ * However, the Type objects in the array are shared.
+ */
+ protected Object clone(){
+ LocalVariables lvs = new LocalVariables(locals.length);
+ for (int i=0; i<locals.length; i++){
+ lvs.locals[i] = this.locals[i];
+ }
+ return lvs;
+ }
+
+ /**
+ * Returns the type of the local variable slot i.
+ */
+ public Type get(int i){
+ return locals[i];
+ }
+
+ /**
+ * Returns a (correctly typed) clone of this object.
+ * This is equivalent to ((LocalVariables) this.clone()).
+ */
+ public LocalVariables getClone(){
+ return (LocalVariables) this.clone();
+ }
+
+ /**
+ * Returns the number of local variable slots this
+ * LocalVariables instance has.
+ */
+ public int maxLocals(){
+ return locals.length;
+ }
+
+ /**
+ * Sets a new Type for the given local variable slot.
+ */
+ public void set(int i, Type type){
+ if (type == Type.BYTE || type == Type.SHORT || type == Type.BOOLEAN || type == Type.CHAR){
+ throw new AssertionViolatedException("LocalVariables do not know about '"+type+"'. Use Type.INT instead.");
+ }
+ locals[i] = type;
+ }
+
+ /*
+ * Fulfills the general contract of Object.equals().
+ */
+ public boolean equals(Object o){
+ if (!(o instanceof LocalVariables)) return false;
+ LocalVariables lv = (LocalVariables) o;
+ if (this.locals.length != lv.locals.length) return false;
+ for (int i=0; i<this.locals.length; i++){
+ if (!this.locals[i].equals(lv.locals[i])){
+ //System.out.println(this.locals[i]+" is not "+lv.locals[i]);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Merges two local variables sets as described in the Java Virtual Machine Specification,
+ * Second Edition, section 4.9.2, page 146.
+ */
+ public void merge(LocalVariables lv){
+
+ if (this.locals.length != lv.locals.length){
+ throw new AssertionViolatedException("Merging LocalVariables of different size?!? From different methods or what?!?");
+ }
+
+ for (int i=0; i<locals.length; i++){
+ merge(lv, i);
+ }
+ }
+
+ /**
+ * Merges a single local variable.
+ *
+ * @see #merge(LocalVariables)
+ */
+ private void merge(LocalVariables lv, int i){
+
+ // We won't accept an unitialized object if we know it was initialized;
+ // compare vmspec2, 4.9.4, last paragraph.
+ if ( (!(locals[i] instanceof UninitializedObjectType)) && (lv.locals[i] instanceof UninitializedObjectType) ){
+ throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object in the local variables detected.");
+ }
+ // Even harder, what about _different_ uninitialized object types?!
+ if ( (!(locals[i].equals(lv.locals[i]))) && (locals[i] instanceof UninitializedObjectType) && (lv.locals[i] instanceof UninitializedObjectType) ){
+ throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object in the local variables detected.");
+ }
+ // If we just didn't know that it was initialized, we have now learned.
+ if (locals[i] instanceof UninitializedObjectType){
+ if (! (lv.locals[i] instanceof UninitializedObjectType)){
+ locals[i] = ((UninitializedObjectType) locals[i]).getInitialized();
+ }
+ }
+ if ((locals[i] instanceof ReferenceType) && (lv.locals[i] instanceof ReferenceType)){
+ if (! locals[i].equals(lv.locals[i])){ // needed in case of two UninitializedObjectType instances
+ Type sup = ((ReferenceType) locals[i]).firstCommonSuperclass((ReferenceType) (lv.locals[i]));
+
+ if (sup != null){
+ locals[i] = sup;
+ }
+ else{
+ // We should have checked this in Pass2!
+ throw new AssertionViolatedException("Could not load all the super classes of '"+locals[i]+"' and '"+lv.locals[i]+"'.");
+ }
+ }
+ }
+ else{
+ if (! (locals[i].equals(lv.locals[i])) ){
+/*TODO
+ if ((locals[i] instanceof org.apache.bcel.generic.ReturnaddressType) && (lv.locals[i] instanceof org.apache.bcel.generic.ReturnaddressType)){
+ //System.err.println("merging "+locals[i]+" and "+lv.locals[i]);
+ throw new AssertionViolatedException("Merging different ReturnAddresses: '"+locals[i]+"' and '"+lv.locals[i]+"'.");
+ }
+*/
+ locals[i] = Type.UNKNOWN;
+ }
+ }
+ }
+
+ /**
+ * Returns a String representation of this object.
+ */
+ public String toString(){
+ String s = new String();
+ for (int i=0; i<locals.length; i++){
+ s += Integer.toString(i)+": "+locals[i]+"\n";
+ }
+ return s;
+ }
+
+ /**
+ * Replaces all occurences of u in this local variables set
+ * with an "initialized" ObjectType.
+ */
+ public void initializeObject(UninitializedObjectType u){
+ for (int i=0; i<locals.length; i++){
+ if (locals[i] == u){
+ locals[i] = u.getInitialized();
+ }
+ }
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/structurals/OperandStack.java b/src/java/org/apache/bcel/verifier/structurals/OperandStack.java
new file mode 100644
index 00000000..d7f50895
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/structurals/OperandStack.java
@@ -0,0 +1,275 @@
+package org.apache.bcel.verifier.structurals;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.generic.*;
+import org.apache.bcel.verifier.exc.*;
+import java.util.*;
+
+/**
+ * This class implements a stack used for symbolic JVM stack simulation.
+ * [It's used an an operand stack substitute.]
+ * Elements of this stack are org.apache.bcel.generic.Type objects.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class OperandStack{
+
+ /** We hold the stack information here. */
+ private ArrayList stack = new ArrayList();
+
+ /** The maximum number of stack slots this OperandStack instance may hold. */
+ private int maxStack;
+
+ /**
+ * Creates an empty stack with a maximum of maxStack slots.
+ */
+ public OperandStack(int maxStack){
+ this.maxStack = maxStack;
+ }
+
+ /**
+ * Creates an otherwise empty stack with a maximum of maxStack slots and
+ * the ObjectType 'obj' at the top.
+ */
+ public OperandStack(int maxStack, ObjectType obj){
+ this.maxStack = maxStack;
+ this.push(obj);
+ }
+ /**
+ * Returns a deep copy of this object; that means, the clone operates
+ * on a new stack. However, the Type objects on the stack are
+ * shared.
+ */
+ protected Object clone(){
+ OperandStack newstack = new OperandStack(this.maxStack);
+ newstack.stack = (ArrayList) this.stack.clone();
+ return newstack;
+ }
+
+ /**
+ * Clears the stack.
+ */
+ public void clear(){
+ stack = new ArrayList();
+ }
+
+ /**
+ * Returns true if and only if this OperandStack
+ * equals another, meaning equal lengths and equal
+ * objects on the stacks.
+ */
+ public boolean equals(Object o){
+ if (!(o instanceof OperandStack)) return false;
+ OperandStack s = (OperandStack) o;
+ return this.stack.equals(s.stack);
+ }
+
+ /**
+ * Returns a (typed!) clone of this.
+ *
+ * @see #clone()
+ */
+ public OperandStack getClone(){
+ return (OperandStack) this.clone();
+ }
+
+ /**
+ * Returns true IFF this OperandStack is empty.
+ */
+ public boolean isEmpty(){
+ return stack.isEmpty();
+ }
+
+ /**
+ * Returns the number of stack slots this stack can hold.
+ */
+ public int maxStack(){
+ return this.maxStack;
+ }
+
+ /**
+ * Returns the element on top of the stack. The element is not popped off the stack!
+ */
+ public Type peek(){
+ return peek(0);
+ }
+
+ /**
+ * Returns the element that's i elements below the top element; that means,
+ * iff i==0 the top element is returned. The element is not popped off the stack!
+ */
+ public Type peek(int i){
+ return (Type) stack.get(size()-i-1);
+ }
+
+ /**
+ * Returns the element on top of the stack. The element is popped off the stack.
+ */
+ public Type pop(){
+ Type e = (Type) stack.remove(size()-1);
+ return e;
+ }
+
+ /**
+ * Pops i elements off the stack. ALWAYS RETURNS "null"!!!
+ */
+ public Type pop(int i){
+ for (int j=0; j<i; j++){
+ pop();
+ }
+ return null;
+ }
+
+ /**
+ * Pushes a Type object onto the stack.
+ */
+ public void push(Type type){
+ if (type == null) throw new AssertionViolatedException("Cannot push NULL onto OperandStack.");
+ if (type == Type.BOOLEAN || type == Type.CHAR || type == Type.BYTE || type == Type.SHORT){
+ throw new AssertionViolatedException("The OperandStack does not know about '"+type+"'; use Type.INT instead.");
+ }
+ if (slotsUsed() >= maxStack){
+ throw new AssertionViolatedException("OperandStack too small, should have thrown proper Exception elsewhere. Stack: "+this);
+ }
+ stack.add(type);
+ }
+
+ /**
+ * Returns the size of this OperandStack; that means, how many Type objects there are.
+ */
+ int size(){
+ return stack.size();
+ }
+
+ /**
+ * Returns the number of stack slots used.
+ * @see #maxStack()
+ */
+ public int slotsUsed(){
+ /* XXX change this to a better implementation using a variable
+ that keeps track of the actual slotsUsed()-value monitoring
+ all push()es and pop()s.
+ */
+ int slots = 0;
+ for (int i=0; i<stack.size(); i++){
+ slots += peek(i).getSize();
+ }
+ return slots;
+ }
+
+ /**
+ * Returns a String representation of this OperandStack instance.
+ */
+ public String toString(){
+ String s = "Slots used: "+slotsUsed()+" MaxStack: "+maxStack+".\n";
+ for (int i=0; i<size(); i++){
+ s+=peek(i)+" (Size: "+peek(i).getSize()+")\n";
+ }
+ return s;
+ }
+
+ /**
+ * Merges another stack state into this instance's stack state.
+ * See the Java Virtual Machine Specification, Second Edition, page 146: 4.9.2
+ * for details.
+ */
+ public void merge(OperandStack s){
+ if ( (slotsUsed() != s.slotsUsed()) || (size() != s.size()) )
+ throw new StructuralCodeConstraintException("Cannot merge stacks of different size:\nOperandStack A:\n"+this+"\nOperandStack B:\n"+s);
+
+ for (int i=0; i<size(); i++){
+ // If the object _was_ initialized and we're supposed to merge
+ // in some uninitialized object, we reject the code (see vmspec2, 4.9.4, last paragraph).
+ if ( (! (stack.get(i) instanceof UninitializedObjectType)) && (s.stack.get(i) instanceof UninitializedObjectType) ){
+ throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object on the stack detected.");
+ }
+ // Even harder, we're not initialized but are supposed to broaden
+ // the known object type
+ if ( (!(stack.get(i).equals(s.stack.get(i)))) && (stack.get(i) instanceof UninitializedObjectType) && (!(s.stack.get(i) instanceof UninitializedObjectType))){
+ throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object on the stack detected.");
+ }
+ // on the other hand...
+ if (stack.get(i) instanceof UninitializedObjectType){ //if we have an uninitialized object here
+ if (! (s.stack.get(i) instanceof UninitializedObjectType)){ //that has been initialized by now
+ stack.set(i, ((UninitializedObjectType) (stack.get(i))).getInitialized() ); //note that.
+ }
+ }
+ if (! stack.get(i).equals(s.stack.get(i))){
+ if ( (stack.get(i) instanceof ReferenceType) &&
+ (s.stack.get(i) instanceof ReferenceType) ){
+ stack.set(i, ((ReferenceType) stack.get(i)).firstCommonSuperclass((ReferenceType) (s.stack.get(i))));
+ }
+ else{
+ throw new StructuralCodeConstraintException("Cannot merge stacks of different types:\nStack A:\n"+this+"\nStack B:\n"+s);
+ }
+ }
+ }
+ }
+
+ /**
+ * Replaces all occurences of u in this OperandStack instance
+ * with an "initialized" ObjectType.
+ */
+ public void initializeObject(UninitializedObjectType u){
+ for (int i=0; i<stack.size(); i++){
+ if (stack.get(i) == u){
+ stack.set(i, u.getInitialized());
+ }
+ }
+ }
+
+}
diff --git a/src/java/org/apache/bcel/verifier/structurals/Pass3bVerifier.java b/src/java/org/apache/bcel/verifier/structurals/Pass3bVerifier.java
new file mode 100644
index 00000000..62373b74
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/structurals/Pass3bVerifier.java
@@ -0,0 +1,366 @@
+package org.apache.bcel.verifier.structurals;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Random;
+import java.util.Vector;
+import org.apache.bcel.Constants;
+import org.apache.bcel.Repository;
+import org.apache.bcel.classfile.*;
+import org.apache.bcel.generic.*;
+import org.apache.bcel.verifier.*;
+import org.apache.bcel.verifier.statics.*;
+import org.apache.bcel.verifier.exc.*;
+
+/**
+ * This PassVerifier verifies a method of class file according to pass 3,
+ * so-called structural verification as described in The Java Virtual Machine
+ * Specification, 2nd edition.
+ * More detailed information is to be found at the do_verify() method's
+ * documentation.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ * @see #do_verify()
+ */
+
+public final class Pass3bVerifier extends PassVerifier{
+ /* TODO: Throughout pass 3b, upper halves of LONG and DOUBLE
+ are represented by Type.UNKNOWN. This should be changed
+ in favour of LONG_Upper and DOUBLE_Upper as in pass 2. */
+
+ /**
+ * An InstructionContextQueue is a utility class that holds
+ * (InstructionContext, ArrayList) pairs in a Queue data structure.
+ * This is used to hold information about InstructionContext objects
+ * externally --- i.e. that information is not saved inside the
+ * InstructionContext object itself. This is useful to save the
+ * execution path of the symbolic execution of the
+ * Pass3bVerifier - this is not information
+ * that belongs into the InstructionContext object itself.
+ * Only at "execute()"ing
+ * time, an InstructionContext object will get the current information
+ * we have about its symbolic execution predecessors.
+ */
+ private static final class InstructionContextQueue{
+ private Vector ics = new Vector(); // Type: InstructionContext
+ private Vector ecs = new Vector(); // Type: ArrayList (of InstructionContext)
+ public void add(InstructionContext ic, ArrayList executionChain){
+ ics.add(ic);
+ ecs.add(executionChain);
+ }
+ public boolean isEmpty(){
+ return ics.isEmpty();
+ }
+ public void remove(){
+ this.remove(0);
+ }
+ public void remove(int i){
+ ics.remove(i);
+ ecs.remove(i);
+ }
+ public InstructionContext getIC(int i){
+ return (InstructionContext) ics.get(i);
+ }
+ public ArrayList getEC(int i){
+ return (ArrayList) ecs.get(i);
+ }
+ public int size(){
+ return ics.size();
+ }
+ } // end Inner Class InstructionContextQueue
+
+ /** In DEBUG mode, the verification algorithm is not randomized. */
+ private static final boolean DEBUG = true;
+
+ /** The Verifier that created this. */
+ private Verifier myOwner;
+
+ /** The method number to verify. */
+ private int method_no;
+
+ /**
+ * This class should only be instantiated by a Verifier.
+ *
+ * @see org.apache.bcel.verifier.Verifier
+ */
+ public Pass3bVerifier(Verifier owner, int method_no){
+ myOwner = owner;
+ this.method_no = method_no;
+ }
+
+ /**
+ * Whenever the outgoing frame
+ * situation of an InstructionContext changes, all its successors are
+ * put [back] into the queue [as if they were unvisited].
+ * The proof of termination is about the existence of a
+ * fix point of frame merging.
+ */
+ private void circulationPump(ControlFlowGraph cfg, InstructionContext start, Frame vanillaFrame, InstConstraintVisitor icv, ExecutionVisitor ev){
+ final Random random = new Random();
+ InstructionContextQueue icq = new InstructionContextQueue();
+
+ start.execute(vanillaFrame, new ArrayList(), icv, ev); // new ArrayList() <=> no Instruction was executed before
+ // => Top-Level routine (no jsr call before)
+ icq.add(start, new ArrayList());
+
+ // LOOP!
+ while (!icq.isEmpty()){
+ InstructionContext u;
+ ArrayList ec;
+ if (!DEBUG){
+ int r = random.nextInt(icq.size());
+ u = icq.getIC(r);
+ ec = icq.getEC(r);
+ icq.remove(r);
+ }
+ else{
+ u = icq.getIC(0);
+ ec = icq.getEC(0);
+ icq.remove(0);
+ }
+
+ ArrayList oldchain = (ArrayList) (ec.clone());
+ ArrayList newchain = (ArrayList) (ec.clone());
+ newchain.add(u);
+
+ if ((u.getInstruction().getInstruction()) instanceof RET){
+//System.err.println(u);
+ // We can only follow _one_ successor, the one after the
+ // JSR that was recently executed.
+ RET ret = (RET) (u.getInstruction().getInstruction());
+ ReturnaddressType t = (ReturnaddressType) u.getOutFrame(oldchain).getLocals().get(ret.getIndex());
+ InstructionContext theSuccessor = cfg.contextOf(t.getTarget());
+
+ // Sanity check
+ InstructionContext lastJSR = null;
+ int skip_jsr = 0;
+ for (int ss=oldchain.size()-1; ss >= 0; ss--){
+ if (skip_jsr < 0){
+ throw new AssertionViolatedException("More RET than JSR in execution chain?!");
+ }
+//System.err.println("+"+oldchain.get(ss));
+ if (((InstructionContext) oldchain.get(ss)).getInstruction().getInstruction() instanceof JsrInstruction){
+ if (skip_jsr == 0){
+ lastJSR = (InstructionContext) oldchain.get(ss);
+ break;
+ }
+ else{
+ skip_jsr--;
+ }
+ }
+ if (((InstructionContext) oldchain.get(ss)).getInstruction().getInstruction() instanceof RET){
+ skip_jsr++;
+ }
+ }
+ if (lastJSR == null){
+ throw new AssertionViolatedException("RET without a JSR before in ExecutionChain?! EC: '"+oldchain+"'.");
+ }
+ JsrInstruction jsr = (JsrInstruction) (lastJSR.getInstruction().getInstruction());
+ if ( theSuccessor != (cfg.contextOf(jsr.physicalSuccessor())) ){
+ throw new AssertionViolatedException("RET '"+u.getInstruction()+"' info inconsistent: jump back to '"+theSuccessor+"' or '"+cfg.contextOf(jsr.physicalSuccessor())+"'?");
+ }
+
+ if (theSuccessor.execute(u.getOutFrame(oldchain), newchain, icv, ev)){
+ icq.add(theSuccessor, (ArrayList) newchain.clone());
+ }
+ }
+ else{// "not a ret"
+
+ // Normal successors. Add them to the queue of successors.
+ InstructionContext[] succs = u.getSuccessors();
+ for (int s=0; s<succs.length; s++){
+ InstructionContext v = succs[s];
+ if (v.execute(u.getOutFrame(oldchain), newchain, icv, ev)){
+ icq.add(v, (ArrayList) newchain.clone());
+ }
+ }
+ }// end "not a ret"
+
+ // Exception Handlers. Add them to the queue of successors.
+ // [subroutines are never protected; mandated by JustIce]
+ ExceptionHandler[] exc_hds = u.getExceptionHandlers();
+ for (int s=0; s<exc_hds.length; s++){
+ InstructionContext v = cfg.contextOf(exc_hds[s].getHandlerStart());
+ // TODO: the "oldchain" and "newchain" is used to determine the subroutine
+ // we're in (by searching for the last JSR) by the InstructionContext
+ // implementation. Therefore, we should not use this chain mechanism
+ // when dealing with exception handlers.
+ // Example: a JSR with an exception handler as its successor does not
+ // mean we're in a subroutine if we go to the exception handler.
+ // We should address this problem later; by now we simply "cut" the chain
+ // by using an empty chain for the exception handlers.
+ //if (v.execute(new Frame(u.getOutFrame(oldchain).getLocals(), new OperandStack (u.getOutFrame().getStack().maxStack(), (exc_hds[s].getExceptionType()==null? Type.THROWABLE : exc_hds[s].getExceptionType())) ), newchain), icv, ev){
+ //icq.add(v, (ArrayList) newchain.clone());
+ if (v.execute(new Frame(u.getOutFrame(oldchain).getLocals(), new OperandStack (u.getOutFrame(oldchain).getStack().maxStack(), (exc_hds[s].getExceptionType()==null? Type.THROWABLE : exc_hds[s].getExceptionType())) ), new ArrayList(), icv, ev)){
+ icq.add(v, new ArrayList());
+ }
+ }
+
+ }// while (!icq.isEmpty()) END
+
+ InstructionHandle ih = start.getInstruction();
+ do{
+ if ((ih.getInstruction() instanceof ReturnInstruction) && (!(cfg.isDead(ih)))) {
+ InstructionContext ic = cfg.contextOf(ih);
+ Frame f = ic.getOutFrame(new ArrayList()); // TODO: This is buggy, we check only the top-level return instructions this way.
+ LocalVariables lvs = f.getLocals();
+ for (int i=0; i<lvs.maxLocals(); i++){
+ if (lvs.get(i) instanceof UninitializedObjectType){
+ this.addMessage("Warning: ReturnInstruction '"+ic+"' may leave method with an uninitialized object in the local variables array '"+lvs+"'.");
+ }
+ }
+ OperandStack os = f.getStack();
+ for (int i=0; i<os.size(); i++){
+ if (os.peek(i) instanceof UninitializedObjectType){
+ this.addMessage("Warning: ReturnInstruction '"+ic+"' may leave method with an uninitialized object on the operand stack '"+os+"'.");
+ }
+ }
+ }
+ }while ((ih = ih.getNext()) != null);
+
+ }
+
+ /**
+ * Pass 3b implements the data flow analysis as described in the Java Virtual
+ * Machine Specification, Second Edition.
+ * Later versions will use LocalVariablesInfo objects to verify if the
+ * verifier-inferred types and the class file's debug information (LocalVariables
+ * attributes) match [TODO].
+ *
+ * @see org.apache.bcel.verifier.statics.LocalVariablesInfo
+ * @see org.apache.bcel.verifier.statics.Pass2Verifier#getLocalVariablesInfo(int)
+ */
+ public VerificationResult do_verify(){
+ if (! myOwner.doPass3a(method_no).equals(VerificationResult.VR_OK)){
+ return VerificationResult.VR_NOTYET;
+ }
+
+ // Pass 3a ran before, so it's safe to assume the JavaClass object is
+ // in the BCEL repository.
+ JavaClass jc = Repository.lookupClass(myOwner.getClassName());
+
+ ConstantPoolGen constantPoolGen = new ConstantPoolGen(jc.getConstantPool());
+ // Init Visitors
+ InstConstraintVisitor icv = new InstConstraintVisitor();
+ icv.setConstantPoolGen(constantPoolGen);
+
+ ExecutionVisitor ev = new ExecutionVisitor();
+ ev.setConstantPoolGen(constantPoolGen);
+
+ Method[] methods = jc.getMethods(); // Method no "method_no" exists, we ran Pass3a before on it!
+
+ try{
+
+ MethodGen mg = new MethodGen(methods[method_no], myOwner.getClassName(), constantPoolGen);
+
+ icv.setMethodGen(mg);
+
+ ////////////// DFA BEGINS HERE ////////////////
+ if (! (mg.isAbstract() || mg.isNative()) ){ // IF mg HAS CODE (See pass 2)
+
+ ControlFlowGraph cfg = new ControlFlowGraph(mg);
+
+ // Build the initial frame situation for this method.
+ Frame f = new Frame(mg.getMaxLocals(),mg.getMaxStack());
+ if ( !mg.isStatic() ){
+ if (mg.getName().equals(Constants.CONSTRUCTOR_NAME)){
+ f._this = new UninitializedObjectType(new ObjectType(jc.getClassName()));
+ f.getLocals().set(0, f._this);
+ }
+ else{
+ f._this = null;
+ f.getLocals().set(0, new ObjectType(jc.getClassName()));
+ }
+ }
+ Type[] argtypes = mg.getArgumentTypes();
+ int twoslotoffset = 0;
+ for (int j=0; j<argtypes.length; j++){
+ if (argtypes[j] == Type.SHORT || argtypes[j] == Type.BYTE || argtypes[j] == Type.CHAR || argtypes[j] == Type.BOOLEAN){
+ argtypes[j] = Type.INT;
+ }
+ f.getLocals().set(twoslotoffset + j + (mg.isStatic()?0:1), argtypes[j]);
+ if (argtypes[j].getSize() == 2){
+ twoslotoffset++;
+ f.getLocals().set(twoslotoffset + j + (mg.isStatic()?0:1), Type.UNKNOWN);
+ }
+ }
+ circulationPump(cfg, cfg.contextOf(mg.getInstructionList().getStart()), f, icv, ev);
+ }
+ }
+ catch (VerifierConstraintViolatedException ce){
+ ce.extendMessage("Constraint violated in method '"+methods[method_no]+"':\n","");
+ return new VerificationResult(VerificationResult.VERIFIED_REJECTED, ce.getMessage());
+ }
+ catch (RuntimeException re){
+ // These are internal errors
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ re.printStackTrace(pw);
+
+ throw new AssertionViolatedException("Some RuntimeException occured while verify()ing class '"+jc.getClassName()+"', method '"+methods[method_no]+"'. Original RuntimeException's stack trace:\n---\n"+sw+"---\n");
+ }
+ return VerificationResult.VR_OK;
+ }
+
+ /** Returns the method number as supplied when instantiating. */
+ public int getMethodNo(){
+ return method_no;
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/structurals/Subroutine.java b/src/java/org/apache/bcel/verifier/structurals/Subroutine.java
new file mode 100644
index 00000000..9f4b8b73
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/structurals/Subroutine.java
@@ -0,0 +1,126 @@
+package org.apache.bcel.verifier.structurals;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.generic.*;
+
+/**
+ * This interface defines properties of JVM bytecode subroutines.
+ * Note that it is 'abused' to maintain the top-level code in a
+ * consistent fashion, too.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public interface Subroutine{
+ /**
+ * Returns all the JsrInstructions that have the
+ * first instruction of this subroutine as their target.
+ * <B>Must not be invoked on the 'top-level subroutine'.</B>
+ */
+ public InstructionHandle[] getEnteringJsrInstructions();
+
+ /**
+ * Returns the one and only RET that leaves the subroutine.
+ * Note that JustIce has a pretty rigid notion of a subroutine.
+ * <B>Must not be invoked on the 'top-level subroutine'.</B>
+ *
+ * @see org.apache.bcel.verifier.structurals.Subroutines
+ */
+ public InstructionHandle getLeavingRET();
+
+ /**
+ * Returns all instructions that together form this subroutine.
+ * Note that an instruction is part of exactly one subroutine
+ * (the top-level code is considered to be a special subroutine) -
+ * else it is not reachable at all (dead code).
+ */
+ public InstructionHandle[] getInstructions();
+
+ /**
+ * Returns if the given InstructionHandle refers to an instruction
+ * that is part of this subroutine. This is a convenience method
+ * that saves iteration over the InstructionHandle objects returned
+ * by getInstructions().
+ *
+ * @see #getInstructions()
+ */
+ public boolean contains(InstructionHandle inst);
+
+ /**
+ * Returns an int[] containing the indices of the local variable slots
+ * accessed by this Subroutine (read-accessed, write-accessed or both);
+ * local variables referenced by subroutines of this subroutine are
+ * not included.
+ *
+ * @see #getRecursivelyAccessedLocalsIndices()
+ */
+ public int[] getAccessedLocalsIndices();
+
+ /**
+ * Returns an int[] containing the indices of the local variable slots
+ * accessed by this Subroutine (read-accessed, write-accessed or both);
+ * local variables referenced by subroutines of this subroutine are
+ * included.
+ *
+ * @see #getAccessedLocalsIndices()
+ */
+ public int[] getRecursivelyAccessedLocalsIndices();
+
+ /**
+ * Returns the subroutines that are directly called from this subroutine.
+ */
+ public Subroutine[] subSubs();
+}
diff --git a/src/java/org/apache/bcel/verifier/structurals/Subroutines.java b/src/java/org/apache/bcel/verifier/structurals/Subroutines.java
new file mode 100644
index 00000000..47b5444e
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/structurals/Subroutines.java
@@ -0,0 +1,668 @@
+package org.apache.bcel.verifier.structurals;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.generic.*;
+import org.apache.bcel.verifier.exc.*;
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+ /**
+ * Instances of this class contain information about the subroutines
+ * found in a code array of a method.
+ * This implementation considers the top-level (the instructions
+ * reachable without a JSR or JSR_W starting off from the first
+ * instruction in a code array of a method) being a special subroutine;
+ * see getTopLevel() for that.
+ * Please note that the definition of subroutines in the Java Virtual
+ * Machine Specification, Second Edition is somewhat incomplete.
+ * Therefore, JustIce uses an own, more rigid notion.
+ * Basically, a subroutine is a piece of code that starts at the target
+ * of a JSR of JSR_W instruction and ends at a corresponding RET
+ * instruction. Note also that the control flow of a subroutine
+ * may be complex and non-linear; and that subroutines may be nested.
+ * JustIce also mandates subroutines not to be protected by exception
+ * handling code (for the sake of control flow predictability).
+ * To understand JustIce's notion of subroutines, please read
+ *
+ * TODO: refer to the paper.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ * @see #getTopLevel()
+ */
+public class Subroutines{
+ /**
+ * This inner class implements the Subroutine interface.
+ */
+ private class SubroutineImpl implements Subroutine{
+ /**
+ * UNSET, a symbol for an uninitialized localVariable
+ * field. This is used for the "top-level" Subroutine;
+ * i.e. no subroutine.
+ */
+ private final int UNSET = -1;
+
+ /**
+ * The Local Variable slot where the first
+ * instruction of this subroutine (an ASTORE) stores
+ * the JsrInstruction's ReturnAddress in and
+ * the RET of this subroutine operates on.
+ */
+ private int localVariable = UNSET;
+
+ /** The instructions that belong to this subroutine. */
+ private HashSet instructions = new HashSet(); // Elements: InstructionHandle
+
+ /*
+ * Refer to the Subroutine interface for documentation.
+ */
+ public boolean contains(InstructionHandle inst){
+ return instructions.contains(inst);
+ }
+
+ /**
+ * The JSR or JSR_W instructions that define this
+ * subroutine by targeting it.
+ */
+ private HashSet theJSRs = new HashSet();
+
+ /**
+ * The RET instruction that leaves this subroutine.
+ */
+ private InstructionHandle theRET;
+
+ /**
+ * Returns a String representation of this object, merely
+ * for debugging purposes.
+ * (Internal) Warning: Verbosity on a problematic subroutine may cause
+ * stack overflow errors due to recursive subSubs() calls.
+ * Don't use this, then.
+ */
+ public String toString(){
+ String ret = "Subroutine: Local variable is '"+localVariable+"', JSRs are '"+theJSRs+"', RET is '"+theRET+"', Instructions: '"+instructions.toString()+"'.";
+
+ ret += " Accessed local variable slots: '";
+ int[] alv = getAccessedLocalsIndices();
+ for (int i=0; i<alv.length; i++){
+ ret += alv[i]+" ";
+ }
+ ret+="'.";
+
+ ret += " Recursively (via subsub...routines) accessed local variable slots: '";
+ alv = getRecursivelyAccessedLocalsIndices();
+ for (int i=0; i<alv.length; i++){
+ ret += alv[i]+" ";
+ }
+ ret+="'.";
+
+ return ret;
+ }
+
+ /**
+ * Sets the leaving RET instruction. Must be invoked after all instructions are added.
+ * Must not be invoked for top-level 'subroutine'.
+ */
+ void setLeavingRET(){
+ if (localVariable == UNSET){
+ throw new AssertionViolatedException("setLeavingRET() called for top-level 'subroutine' or forgot to set local variable first.");
+ }
+ Iterator iter = instructions.iterator();
+ InstructionHandle ret = null;
+ while(iter.hasNext()){
+ InstructionHandle actual = (InstructionHandle) iter.next();
+ if (actual.getInstruction() instanceof RET){
+ if (ret != null){
+ throw new StructuralCodeConstraintException("Subroutine with more then one RET detected: '"+ret+"' and '"+actual+"'.");
+ }
+ else{
+ ret = actual;
+ }
+ }
+ }
+ if (ret == null){
+ throw new StructuralCodeConstraintException("Subroutine without a RET detected.");
+ }
+ if (((RET) ret.getInstruction()).getIndex() != localVariable){
+ throw new StructuralCodeConstraintException("Subroutine uses '"+ret+"' which does not match the correct local variable '"+localVariable+"'.");
+ }
+ theRET = ret;
+ }
+
+ /*
+ * Refer to the Subroutine interface for documentation.
+ */
+ public InstructionHandle[] getEnteringJsrInstructions(){
+ if (this == TOPLEVEL) {
+ throw new AssertionViolatedException("getLeavingRET() called on top level pseudo-subroutine.");
+ }
+ InstructionHandle[] jsrs = new InstructionHandle[theJSRs.size()];
+ return (InstructionHandle[]) (theJSRs.toArray(jsrs));
+ }
+
+ /**
+ * Adds a new JSR or JSR_W that has this subroutine as its target.
+ */
+ public void addEnteringJsrInstruction(InstructionHandle jsrInst){
+ if ( (jsrInst == null) || (! (jsrInst.getInstruction() instanceof JsrInstruction))){
+ throw new AssertionViolatedException("Expecting JsrInstruction InstructionHandle.");
+ }
+ if (localVariable == UNSET){
+ throw new AssertionViolatedException("Set the localVariable first!");
+ }
+ else{
+ // Something is wrong when an ASTORE is targeted that does not operate on the same local variable than the rest of the
+ // JsrInstruction-targets and the RET.
+ // (We don't know out leader here so we cannot check if we're really targeted!)
+ if (localVariable != ((ASTORE) (((JsrInstruction) jsrInst.getInstruction()).getTarget().getInstruction())).getIndex()){
+ throw new AssertionViolatedException("Setting a wrong JsrInstruction.");
+ }
+ }
+ theJSRs.add(jsrInst);
+ }
+
+ /*
+ * Refer to the Subroutine interface for documentation.
+ */
+ public InstructionHandle getLeavingRET(){
+ if (this == TOPLEVEL) {
+ throw new AssertionViolatedException("getLeavingRET() called on top level pseudo-subroutine.");
+ }
+ return theRET;
+ }
+
+ /*
+ * Refer to the Subroutine interface for documentation.
+ */
+ public InstructionHandle[] getInstructions(){
+ InstructionHandle[] ret = new InstructionHandle[instructions.size()];
+ return (InstructionHandle[]) instructions.toArray(ret);
+ }
+
+ /*
+ * Adds an instruction to this subroutine.
+ * All instructions must have been added before invoking setLeavingRET().
+ * @see #setLeavingRET
+ */
+ void addInstruction(InstructionHandle ih){
+ if (theRET != null){
+ throw new AssertionViolatedException("All instructions must have been added before invoking setLeavingRET().");
+ }
+ instructions.add(ih);
+ }
+
+ /* Satisfies Subroutine.getRecursivelyAccessedLocalsIndices(). */
+ public int[] getRecursivelyAccessedLocalsIndices(){
+ HashSet s = new HashSet();
+ int[] lvs = getAccessedLocalsIndices();
+ for (int j=0; j<lvs.length; j++){
+ s.add(new Integer(lvs[j]));
+ }
+ _getRecursivelyAccessedLocalsIndicesHelper(s, this.subSubs());
+ int[] ret = new int[s.size()];
+ Iterator i = s.iterator();
+ int j=-1;
+ while (i.hasNext()){
+ j++;
+ ret[j] = ((Integer) i.next()).intValue();
+ }
+ return ret;
+ }
+
+ /**
+ * A recursive helper method for getRecursivelyAccessedLocalsIndices().
+ * @see #getRecursivelyAccessedLocalsIndices()
+ */
+ private void _getRecursivelyAccessedLocalsIndicesHelper(HashSet s, Subroutine[] subs){
+ for (int i=0; i<subs.length; i++){
+ int[] lvs = subs[i].getAccessedLocalsIndices();
+ for (int j=0; j<lvs.length; j++){
+ s.add(new Integer(lvs[j]));
+ }
+ if(subs[i].subSubs().length != 0){
+ _getRecursivelyAccessedLocalsIndicesHelper(s, subs[i].subSubs());
+ }
+ }
+ }
+
+ /*
+ * Satisfies Subroutine.getAccessedLocalIndices().
+ */
+ public int[] getAccessedLocalsIndices(){
+ //TODO: Implement caching.
+ HashSet acc = new HashSet();
+ if (theRET == null && this != TOPLEVEL){
+ throw new AssertionViolatedException("This subroutine object must be built up completely before calculating accessed locals.");
+ }
+ Iterator i = instructions.iterator();
+ while (i.hasNext()){
+ InstructionHandle ih = (InstructionHandle) i.next();
+ // RET is not a LocalVariableInstruction in the current version of BCEL.
+ if (ih.getInstruction() instanceof LocalVariableInstruction || ih.getInstruction() instanceof RET){
+ int idx = ((IndexedInstruction) (ih.getInstruction())).getIndex();
+ acc.add(new Integer(idx));
+ // LONG? DOUBLE?.
+ try{
+ // LocalVariableInstruction instances are typed without the need to look into
+ // the constant pool.
+ if (ih.getInstruction() instanceof LocalVariableInstruction){
+ int s = ((LocalVariableInstruction) ih.getInstruction()).getType(null).getSize();
+ if (s==2) acc.add(new Integer(idx+1));
+ }
+ }
+ catch(RuntimeException re){
+ throw new AssertionViolatedException("Oops. BCEL did not like NULL as a ConstantPoolGen object.");
+ }
+ }
+ }
+
+ int[] ret = new int[acc.size()];
+ i = acc.iterator();
+ int j=-1;
+ while (i.hasNext()){
+ j++;
+ ret[j] = ((Integer) i.next()).intValue();
+ }
+ return ret;
+ }
+
+ /*
+ * Satisfies Subroutine.subSubs().
+ */
+ public Subroutine[] subSubs(){
+ HashSet h = new HashSet();
+
+ Iterator i = instructions.iterator();
+ while (i.hasNext()){
+ Instruction inst = ((InstructionHandle) i.next()).getInstruction();
+ if (inst instanceof JsrInstruction){
+ InstructionHandle targ = ((JsrInstruction) inst).getTarget();
+ h.add(getSubroutine(targ));
+ }
+ }
+ Subroutine[] ret = new Subroutine[h.size()];
+ return (Subroutine[]) h.toArray(ret);
+ }
+
+ /*
+ * Sets the local variable slot the ASTORE that is targeted
+ * by the JsrInstructions of this subroutine operates on.
+ * This subroutine's RET operates on that same local variable
+ * slot, of course.
+ */
+ void setLocalVariable(int i){
+ if (localVariable != UNSET){
+ throw new AssertionViolatedException("localVariable set twice.");
+ }
+ else{
+ localVariable = i;
+ }
+ }
+
+ /**
+ * The default constructor.
+ */
+ public SubroutineImpl(){
+ }
+
+ }// end Inner Class SubrouteImpl
+
+ /**
+ * The Hashtable containing the subroutines found.
+ * Key: InstructionHandle of the leader of the subroutine.
+ * Elements: SubroutineImpl objects.
+ */
+ private Hashtable subroutines = new Hashtable();
+
+ /**
+ * This is referring to a special subroutine, namely the
+ * top level. This is not really a subroutine but we use
+ * it to distinguish between top level instructions and
+ * unreachable instructions.
+ */
+ public final Subroutine TOPLEVEL;
+
+ /**
+ * Constructor.
+ * @param il A MethodGen object representing method to
+ * create the Subroutine objects of.
+ */
+ public Subroutines(MethodGen mg){
+
+ InstructionHandle[] all = mg.getInstructionList().getInstructionHandles();
+ CodeExceptionGen[] handlers = mg.getExceptionHandlers();
+
+ // Define our "Toplevel" fake subroutine.
+ TOPLEVEL = new SubroutineImpl();
+
+ // Calculate "real" subroutines.
+ HashSet sub_leaders = new HashSet(); // Elements: InstructionHandle
+ InstructionHandle ih = all[0];
+ for (int i=0; i<all.length; i++){
+ Instruction inst = all[i].getInstruction();
+ if (inst instanceof JsrInstruction){
+ sub_leaders.add(((JsrInstruction) inst).getTarget());
+ }
+ }
+
+ // Build up the database.
+ Iterator iter = sub_leaders.iterator();
+ while (iter.hasNext()){
+ SubroutineImpl sr = new SubroutineImpl();
+ InstructionHandle astore = (InstructionHandle) (iter.next());
+ sr.setLocalVariable( ((ASTORE) (astore.getInstruction())).getIndex() );
+ subroutines.put(astore, sr);
+ }
+
+ // Fake it a bit. We want a virtual "TopLevel" subroutine.
+ subroutines.put(all[0], TOPLEVEL);
+ sub_leaders.add(all[0]);
+
+ // Tell the subroutines about their JsrInstructions.
+ // Note that there cannot be a JSR targeting the top-level
+ // since "Jsr 0" is disallowed in Pass 3a.
+ // Instructions shared by a subroutine and the toplevel are
+ // disallowed and checked below, after the BFS.
+ for (int i=0; i<all.length; i++){
+ Instruction inst = all[i].getInstruction();
+ if (inst instanceof JsrInstruction){
+ InstructionHandle leader = ((JsrInstruction) inst).getTarget();
+ ((SubroutineImpl) getSubroutine(leader)).addEnteringJsrInstruction(all[i]);
+ }
+ }
+
+ // Now do a BFS from every subroutine leader to find all the
+ // instructions that belong to a subroutine.
+ HashSet instructions_assigned = new HashSet(); // we don't want to assign an instruction to two or more Subroutine objects.
+
+ Hashtable colors = new Hashtable(); //Graph colouring. Key: InstructionHandle, Value: java.awt.Color .
+
+ iter = sub_leaders.iterator();
+ while (iter.hasNext()){
+ // Do some BFS with "actual" as the root of the graph.
+ InstructionHandle actual = (InstructionHandle) (iter.next());
+ // Init colors
+ for (int i=0; i<all.length; i++){
+ colors.put(all[i], Color.white);
+ }
+ colors.put(actual, Color.gray);
+ // Init Queue
+ ArrayList Q = new ArrayList();
+ Q.add(actual); // add(Obj) adds to the end, remove(0) removes from the start.
+
+ /* BFS ALGORITHM MODIFICATION: Start out with multiple "root" nodes, as exception handlers are starting points of top-level code, too. [why top-level? TODO: Refer to the special JustIce notion of subroutines.]*/
+ if (actual == all[0]){
+ for (int j=0; j<handlers.length; j++){
+ colors.put(handlers[j].getHandlerPC(), Color.gray);
+ Q.add(handlers[j].getHandlerPC());
+ }
+ }
+ /* CONTINUE NORMAL BFS ALGORITHM */
+
+ // Loop until Queue is empty
+ while (Q.size() != 0){
+ InstructionHandle u = (InstructionHandle) Q.remove(0);
+ InstructionHandle[] successors = getSuccessors(u);
+ for (int i=0; i<successors.length; i++){
+ if (((Color) colors.get(successors[i])) == Color.white){
+ colors.put(successors[i], Color.gray);
+ Q.add(successors[i]);
+ }
+ }
+ colors.put(u, Color.black);
+ }
+ // BFS ended above.
+ for (int i=0; i<all.length; i++){
+ if (colors.get(all[i]) == Color.black){
+ ((SubroutineImpl) (actual==all[0]?getTopLevel():getSubroutine(actual))).addInstruction(all[i]);
+ if (instructions_assigned.contains(all[i])){
+ throw new StructuralCodeConstraintException("Instruction '"+all[i]+"' is part of more than one subroutine (or of the top level and a subroutine).");
+ }
+ else{
+ instructions_assigned.add(all[i]);
+ }
+ }
+ }
+ if (actual != all[0]){// If we don't deal with the top-level 'subroutine'
+ ((SubroutineImpl) getSubroutine(actual)).setLeavingRET();
+ }
+ }
+
+ // Now make sure no instruction of a Subroutine is protected by exception handling code
+ // as is mandated by JustIces notion of subroutines.
+ for (int i=0; i<handlers.length; i++){
+ InstructionHandle _protected = handlers[i].getStartPC();
+ while (_protected != handlers[i].getEndPC().getNext()){// Note the inclusive/inclusive notation of "generic API" exception handlers!
+ Enumeration subs = subroutines.elements();
+ while (subs.hasMoreElements()){
+ Subroutine sub = (Subroutine) subs.nextElement();
+ if (sub != subroutines.get(all[0])){ // We don't want to forbid top-level exception handlers.
+ if (sub.contains(_protected)){
+ throw new StructuralCodeConstraintException("Subroutine instruction '"+_protected+"' is protected by an exception handler, '"+handlers[i]+"'. This is forbidden by the JustIce verifier due to its clear definition of subroutines.");
+ }
+ }
+ }
+ _protected = _protected.getNext();
+ }
+ }
+
+ // Now make sure no subroutine is calling a subroutine
+ // that uses the same local variable for the RET as themselves
+ // (recursively).
+ // This includes that subroutines may not call themselves
+ // recursively, even not through intermediate calls to other
+ // subroutines.
+ noRecursiveCalls(getTopLevel(), new HashSet());
+
+ }
+
+ /**
+ * This (recursive) utility method makes sure that
+ * no subroutine is calling a subroutine
+ * that uses the same local variable for the RET as themselves
+ * (recursively).
+ * This includes that subroutines may not call themselves
+ * recursively, even not through intermediate calls to other
+ * subroutines.
+ *
+ * @throws StructuralCodeConstraintException if the above constraint is not satisfied.
+ */
+ private void noRecursiveCalls(Subroutine sub, HashSet set){
+ Subroutine[] subs = sub.subSubs();
+
+ for (int i=0; i<subs.length; i++){
+ int index = ((RET) (subs[i].getLeavingRET().getInstruction())).getIndex();
+
+ if (!set.add(new Integer(index))){
+ // Don't use toString() here because of possibly infinite recursive subSubs() calls then.
+ SubroutineImpl si = (SubroutineImpl) subs[i];
+ throw new StructuralCodeConstraintException("Subroutine with local variable '"+si.localVariable+"', JSRs '"+si.theJSRs+"', RET '"+si.theRET+"' is called by a subroutine which uses the same local variable index as itself; maybe even a recursive call? JustIce's clean definition of a subroutine forbids both.");
+ }
+
+ noRecursiveCalls(subs[i], set);
+
+ set.remove(new Integer(index));
+ }
+ }
+
+ /**
+ * Returns the Subroutine object associated with the given
+ * leader (that is, the first instruction of the subroutine).
+ * You must not use this to get the top-level instructions
+ * modeled as a Subroutine object.
+ *
+ * @see #getTopLevel()
+ */
+ public Subroutine getSubroutine(InstructionHandle leader){
+ Subroutine ret = (Subroutine) subroutines.get(leader);
+
+ if (ret == null){
+ throw new AssertionViolatedException("Subroutine requested for an InstructionHandle that is not a leader of a subroutine.");
+ }
+
+ if (ret == TOPLEVEL){
+ throw new AssertionViolatedException("TOPLEVEL special subroutine requested; use getTopLevel().");
+ }
+
+ return ret;
+ }
+
+ /**
+ * Returns the subroutine object associated with the
+ * given instruction. This is a costly operation, you
+ * should consider using getSubroutine(InstructionHandle).
+ * Returns 'null' if the given InstructionHandle lies
+ * in so-called 'dead code', i.e. code that can never
+ * be executed.
+ *
+ * @see #getSubroutine(InstructionHandle)
+ * @see #getTopLevel()
+ */
+ public Subroutine subroutineOf(InstructionHandle any){
+ Iterator i = subroutines.values().iterator();
+ while (i.hasNext()){
+ Subroutine s = (Subroutine) i.next();
+ if (s.contains(any)) return s;
+ }
+System.err.println("DEBUG: Please verify '"+any+"' lies in dead code.");
+ return null;
+ //throw new AssertionViolatedException("No subroutine for InstructionHandle found (DEAD CODE?).");
+ }
+
+ /**
+ * For easy handling, the piece of code that is <B>not</B> a
+ * subroutine, the top-level, is also modeled as a Subroutine
+ * object.
+ * It is a special Subroutine object where <B>you must not invoke
+ * getEnteringJsrInstructions() or getLeavingRET()</B>.
+ *
+ * @see Subroutine#getEnteringJsrInstructions()
+ * @see Subroutine#getLeavingRET()
+ */
+ public Subroutine getTopLevel(){
+ return TOPLEVEL;
+ }
+ /**
+ * A utility method that calculates the successors of a given InstructionHandle
+ * <B>in the same subroutine</B>. That means, a RET does not have any successors
+ * as defined here. A JsrInstruction has its physical successor as its successor
+ * (opposed to its target) as defined here.
+ */
+ private static InstructionHandle[] getSuccessors(InstructionHandle instruction){
+ final InstructionHandle[] empty = new InstructionHandle[0];
+ final InstructionHandle[] single = new InstructionHandle[1];
+ final InstructionHandle[] pair = new InstructionHandle[2];
+
+ Instruction inst = instruction.getInstruction();
+
+ if (inst instanceof RET){
+ return empty;
+ }
+
+ // Terminates method normally.
+ if (inst instanceof ReturnInstruction){
+ return empty;
+ }
+
+ // Terminates method abnormally, because JustIce mandates
+ // subroutines not to be protected by exception handlers.
+ if (inst instanceof ATHROW){
+ return empty;
+ }
+
+ // See method comment.
+ if (inst instanceof JsrInstruction){
+ single[0] = instruction.getNext();
+ return single;
+ }
+
+ if (inst instanceof GotoInstruction){
+ single[0] = ((GotoInstruction) inst).getTarget();
+ return single;
+ }
+
+ if (inst instanceof BranchInstruction){
+ if (inst instanceof Select){
+ // BCEL's getTargets() returns only the non-default targets,
+ // thanks to Eli Tilevich for reporting.
+ InstructionHandle[] matchTargets = ((Select) inst).getTargets();
+ InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1];
+ ret[0] = ((Select) inst).getTarget();
+ System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length);
+ return ret;
+ }
+ else{
+ pair[0] = instruction.getNext();
+ pair[1] = ((BranchInstruction) inst).getTarget();
+ return pair;
+ }
+ }
+
+ // default case: Fall through.
+ single[0] = instruction.getNext();
+ return single;
+ }
+
+ /**
+ * Returns a String representation of this object; merely for debugging puposes.
+ */
+ public String toString(){
+ return "---\n"+subroutines.toString()+"\n---\n";
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/structurals/UninitializedObjectType.java b/src/java/org/apache/bcel/verifier/structurals/UninitializedObjectType.java
new file mode 100644
index 00000000..ac9bbddb
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/structurals/UninitializedObjectType.java
@@ -0,0 +1,97 @@
+package org.apache.bcel.verifier.structurals;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.*;
+import org.apache.bcel.generic.*;
+
+/**
+ * This class represents an uninitialized object type; see The Java
+ * Virtual Machine Specification, Second Edition, page 147: 4.9.4 for
+ * more details.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class UninitializedObjectType extends ReferenceType implements Constants{
+
+ /** The "initialized" version. */
+ private ObjectType initialized;
+
+ /** Creates a new instance. */
+ public UninitializedObjectType(ObjectType t){
+ super(T_UNKNOWN, "<UNINITIALIZED OBJECT OF TYPE '"+t.getClassName()+"'>");
+ initialized = t;
+ }
+
+ /**
+ * Returns the ObjectType of the same class as the one of the uninitialized object
+ * represented by this UninitializedObjectType instance.
+ */
+ public ObjectType getInitialized(){
+ return initialized;
+ }
+
+ /**
+ * Returns true on equality of this and o.
+ * Equality means the ObjectType instances of "initialized"
+ * equal one another in this and the o instance.
+ *
+ */
+ public boolean equals(Object o){
+ if (! (o instanceof UninitializedObjectType)) return false;
+ return initialized.equals(((UninitializedObjectType)o).initialized);
+ }
+}
diff --git a/src/java/org/apache/bcel/verifier/structurals/package.html b/src/java/org/apache/bcel/verifier/structurals/package.html
new file mode 100644
index 00000000..915ff5e9
--- /dev/null
+++ b/src/java/org/apache/bcel/verifier/structurals/package.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+$Id$
+-->
+</head>
+<body bgcolor="white">
+
+Provides a PassVerifier class mostly used internally by JustIce, yielding a control flow graph for public use as
+a nice side effect.
+
+<h2>Package Specification</h2>
+
+Contained in this package is a PassVerifier class for use with the JustIce verifier and its utility classes.
+Only the pass performing what Sun calls "Structural Constraints on Java Virtual Machine Code"
+has a PassVerifier class here. JustIce calls this pass "Pass 3b".
+
+<h2>Related Documentation</h2>
+
+For a simple demonstration of JustIce working, please see:
+<ul>
+ <li><a href="http://www.inf.fu-berlin.de/~ehaase/cgi-html/Verifier.html">A WWW front-end for JustIce.</a>
+</ul>
+
+</body>
+</html>