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

ArrayIndexOutOfBoundsException in -server mode

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P3 P3
    • None
    • 1.4.2
    • hotspot
    • x86
    • windows_xp



      Name: tb29552 Date: 01/12/2004


      FULL PRODUCT VERSION :
      java version "1.4.2_03"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_03-b02)
      Java HotSpot(TM) Server VM (build 1.4.2_03-b02, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows XP [Version 5.1.2600]

      A DESCRIPTION OF THE PROBLEM :
      The attached test case does not work correctly with java using the -server option. It works fine without the -server option.

      In particular, when run in -server mode, the test case throws ArrayIndexOutOfBounds exceptions. I have also included a line in the code which demonstrates an inconsistency in the JVM; inside a loop

       while (searchPos != 0x0ffff) {
          ...
       }

      I demonstrate searchPos to in fact be equal to 0x0ffff.

      The problem appears to be a timing issue. If I run the code in an IDE such as JBuilder and step through, the problem disappears. I can also sometimes get the problem to disappear by adding unrelated code at various points in the program (such as immediately before the while loop)

      The problem appears consistently if I run the test repeatedly in a loop. (The main method of the test case invokes the test 200 times.) If I run the test only a single times, the error sometimes appears and sometimes does not.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      javac NewDeflater.java
      java -server NewDeflater

      I used version 1.4.2_03 of the JDK to produce this problem, but also experienced the problem with every other JDK I tried.

      Random data is not necessary to produce the problem; I was able to produce the bug using Windows binary files, etc.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The program should terminate without throwing any exceptions or producing any output. This is the behavior seen in client mode.

      ACTUAL -
      The test case, which was run in a loop, repeatedly threw ArrayIndexOutOfBounds exceptions. Moreover, it printed debugging output to the console, which proved that there was internal inconsistency in the VM.

      See error message below; the "0: 65535 65535 true" etc. was generated by System.out.println statements in my code.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      0: 65535 65535 true
      java.lang.ArrayIndexOutOfBoundsException: 65535
              at NewDeflater._newhash_FindBestMatch(NewDeflater.java:54)
              at NewDeflater.CompressDataInWindow(NewDeflater.java:73)
              at NewDeflater.main(NewDeflater.java:108)
      0: 65535 65535 false
      java.lang.ArrayIndexOutOfBoundsException: 65535
              at NewDeflater._newhash_FindBestMatch(NewDeflater.java:54)
              at NewDeflater.CompressDataInWindow(NewDeflater.java:73)
              at NewDeflater.main(NewDeflater.java:108)
      0: 65535 65535 false
      java.lang.ArrayIndexOutOfBoundsException: 65535
              at NewDeflater._newhash_FindBestMatch(NewDeflater.java:54)
              at NewDeflater.CompressDataInWindow(NewDeflater.java:73)
              at NewDeflater.main(NewDeflater.java:108)
      0: 65535 65535 false
      java.lang.ArrayIndexOutOfBoundsException: 65535
              at NewDeflater._newhash_FindBestMatch(NewDeflater.java:54)
              at NewDeflater.CompressDataInWindow(NewDeflater.java:73)
              at NewDeflater.main(NewDeflater.java:108)
      0: 65535 65535 false
      java.lang.ArrayIndexOutOfBoundsException: 65535
              at NewDeflater._newhash_FindBestMatch(NewDeflater.java:54)
              at NewDeflater.CompressDataInWindow(NewDeflater.java:73)
              at NewDeflater.main(NewDeflater.java:108)
      0: 65535 65535 false
      java.lang.ArrayIndexOutOfBoundsException: 65535
              at NewDeflater._newhash_FindBestMatch(NewDeflater.java:54)
              at NewDeflater.CompressDataInWindow(NewDeflater.java:73)
              at NewDeflater.main(NewDeflater.java:108)
      0: 65535 65535 false
      java.lang.ArrayIndexOutOfBoundsException: 65535
              at NewDeflater._newhash_FindBestMatch(NewDeflater.java:54)
              at NewDeflater.CompressDataInWindow(NewDeflater.java:73)
              at NewDeflater.main(NewDeflater.java:108)
      0: 65535 65535 false
      java.lang.ArrayIndexOutOfBoundsException: 65535
              at NewDeflater._newhash_FindBestMatch(NewDeflater.java:54)
              at NewDeflater.CompressDataInWindow(NewDeflater.java:73)
              at NewDeflater.main(NewDeflater.java:108)
      0: 65535 65535 false
      java.lang.ArrayIndexOutOfBoundsException: 65535
              at NewDeflater._newhash_FindBestMatch(NewDeflater.java:54)
              at NewDeflater.CompressDataInWindow(NewDeflater.java:73)
              at NewDeflater.main(NewDeflater.java:108)

      (continues)

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      // This is stripped source code to do zip compression, stripped as
      // much as was possible while still producing the bug.

      class NewDeflater {

       private static final int WINDOW_SIZE = 65535; // leaving 0xffff for a null reference.
       private static final short HASH_NULL = -1;

       byte[] window;
       int window_off;
       int window_end;

       /** Hash table functions **/

       public static int HASHTABLE_SIZE = 16384;
       short[] hashHeads;
       short[] hashChains;

       private int HashFunction(int byte1, int byte2, int byte3) {
         return (((byte1 << 6) ^ (byte2 << 3) ^ byte3) & 0x3fff);
       }

       private void HashAdd(int byte1, int byte2, int byte3, int location) {
         int slot = HashFunction(byte1, byte2, byte3);
         short prev = hashHeads[slot];
         hashHeads[slot] = (short) location;
         hashChains[location] = (short) prev;
       }

       int BestMatchLength;
       int BestMatchLocation;

       public NewDeflater() {
         window = new byte[WINDOW_SIZE];
         hashHeads = new short[HASHTABLE_SIZE];
         for (int i = 0; i < HASHTABLE_SIZE; i++)
           hashHeads[i] = HASH_NULL; // a null reference. eventually: -1.
         hashChains = new short[WINDOW_SIZE];
         for (int i = 0; i < WINDOW_SIZE; i++)
           hashChains[i] = HASH_NULL;
         window_off = 1;
         window_end = 1;
       }

       // Parameters:
       // htr: the hash-table root, the first potential match to search.
       private void _newhash_FindBestMatch(int htr) {
         int searchPos = (int) hashHeads[htr] & 0xffff;
         int currpos = window_off;
         while (searchPos != 0x0ffff) {
           // HERE IS PROOF OF THE JVM BUG:
           if (searchPos + BestMatchLength > 65534) {
             System.out.println("" + (searchPos - 0x0ffff) + ": " + searchPos + " " + 0x0ffff + " " + (searchPos == 0x0ffff)); //(searchPos == 0xffff));
           }
           // Determine the length of the match.
           int currlen = 0;
           while (currlen < 258 && (window[searchPos + currlen] == window[currpos + currlen]))
             currlen++;
           if (currlen > BestMatchLength) {
             BestMatchLength = currlen;
             BestMatchLocation = searchPos;
             if (currlen == 258) return;
           }
           searchPos = (int) hashChains[searchPos] & 0xffff;
         }
       }

        private void CompressDataInWindow() {
         int htr;

         while (window_off < window_end - 258) {
           htr = HashFunction(window[window_off], window[window_off+1], window[window_off+2]);
           BestMatchLength = 0;

           if (hashHeads[htr] != HASH_NULL)
             _newhash_FindBestMatch(htr);

           if (BestMatchLength > 2) {

             // now that we are done with the hash table, add the present entry.
             HashAdd(window[window_off], window[window_off+1], window[window_off+2], window_off);

             // add entries to the hash table for the skipped portion.
             int limit = window_off + BestMatchLength;
             window_off++;

             while (window_off < limit) {
               HashAdd(window[window_off], window[window_off+1], window[window_off+2], window_off);
               window_off++;
             }
           }
           else
             HashAdd(window[window_off], window[window_off+1], window[window_off+2], window_off);
         }
       }

       public void setInput(byte[] buf, int off, int len) {
         System.arraycopy(buf, off, window, window_end, len);
         window_end += len;
       }

       public static void main(String[] args) {
        byte[] test = new byte[40000];
        java.util.Random r = new java.util.Random();
        r.nextBytes(test);

        for (int i = 0; i < 200; i++) {
         try {
           NewDeflater def = new NewDeflater();
           def.setInput(test, 0, test.length);
           def.CompressDataInWindow();
         }
         catch (Exception ex) {
           ex.printStackTrace();
         }
         }
       }
      }
      ---------- END SOURCE ----------
      (Review ID: 231828)
      ======================================================================

            rasbold Chuck Rasbold
            tbell Tim Bell
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: