Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-5092850

RedefineClasses causes VerifyError

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P3 P3
    • 6
    • 6
    • hotspot
    • mustang
    • x86, sparc
    • solaris_2.5.1, solaris_9

        Name: tb29552 Date: 08/26/2004


        FULL PRODUCT VERSION :
        java version "1.5.0-beta3"
        Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta3-b60)
        Java HotSpot(TM) Client VM (build 1.5.0-beta3-b60, mixed mode, sharing)


        ADDITIONAL OS VERSION INFORMATION :
        Linux deepspace1 2.4.22-10mdk #1 Thu Sep 18 12:30:58 CEST 2003 i686 unknown unknown GNU/Linux

        A DESCRIPTION OF THE PROBLEM :
        I have added a very simple example, that reproduces the problem:

        The class (test.Startup) contains the instrumentation. It does nothing but replace the loaded class "test.Instrumented" with a new version (which is exactly the same as the old version). The loaded byte arrays is dumped to a file, so it is possible to compare it to the original classfile.

        After reloading the class, invoking the constructor of "test.Instrumented" leads to a VerifyError. But since the classfile is exactly the same as before this should not happen.


        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        1.) Make a directory "test"
        2.) Create the three java files in this directory ("Startup.java", "Instrumentation.java", "Test.java")
        3.) Save the manifest as "manifest.mf"
        3.) Compile the classes
        javac test/*.java
        4.) Build the jar file
        jar -cvfm test.jar manifest.mf test/Startup.class
        5.) Run the Test
        java -classpath . -javaagent:test.jar test.Test
        6.) A VerifyError is thrown.
        7.) Observe that result.dump has exactly the same contents as test/Instrumentation.class

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        No Exception.
        ACTUAL -
        An VerifyError is thrown.

        ERROR MESSAGES/STACK TRACES THAT OCCUR :
        Exception in thread "main" java.lang.VerifyError: (class: test/Instrument, method: <init> signature: ()V) Illegal constant pool index
                at test.Test.main(Test.java:12)


        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        ----------------------------------------------
        Instrumented.java:
        ----------------------------------------------
        package test;

        public class Instrument {
        }
        ----------------------------------------------
        Startup.java:
        ----------------------------------------------
        package test;

        import java.io.FileOutputStream;
        import java.io.InputStream;
        import java.io.IOException;
        import java.io.ByteArrayOutputStream;
        import java.lang.instrument.Instrumentation;
        import java.lang.instrument.ClassDefinition;

        public class Startup {
            private static Instrumentation instrumentation;

            public static void premain(String options, Instrumentation instrumentation) {
                Startup.instrumentation = instrumentation;
            }

            public static void init()
                throws Exception {
         
                Class[] allClasses = instrumentation.getAllLoadedClasses();
          
                for (int i=0; i<allClasses.length; i++) {
                    String className = allClasses[i].getName();
                    if ("test.Instrument".equals(className)) {
                        byte[] classfileBuffer = getClassFileBuffer(className, allClasses[i].getClassLoader());
                        instrumentation.redefineClasses(new ClassDefinition[] {new ClassDefinition(allClasses[i], classfileBuffer)});

                        FileOutputStream fout = new FileOutputStream("result.dump");
                        fout.write(classfileBuffer);
                        fout.close();
                    }
                 }
            }

            private static final byte[] getClassFileBuffer(String className, ClassLoader cl) throws IOException {
                InputStream is = cl.getResourceAsStream(className.replace('.', '/') + ".class");
                byte[] buf = new byte[1024];

                ByteArrayOutputStream baos = new ByteArrayOutputStream(is.available());
                int read;
                do {
                    read = is.read(buf);
                    if (read > -1) {
                        baos.write(buf, 0, read);
                    }
                } while (read > -1);

                is.close();
                return baos.toByteArray();
            }
        }
         
        ----------------------------------------------
        Test.java:
        ----------------------------------------------
        package test;

        public class Test {

            public static void main(String[] args) throws Exception {
                // load the class
                System.out.println(Instrument.class.getName());

                Startup.init();

                // try to use it again -> causes VerifyError
                new Instrument();
            }
        }
        ----------------------------------------------
        manifest.mf:
        ----------------------------------------------
        premain-class: test.Startup
        Can-Redefine-Classes: true


        ---------- END SOURCE ----------
        (Incident Review ID: 300972)
        ======================================================================
        ###@###.### 10/7/04 00:12 GMT

              alanb Alan Bateman
              tbell Tim Bell
              Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: