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

REGRESSION: JarEntry.getCertificates() returns null when memory is strained

XMLWordPrintable

      This problem is hindering Oracle's ability to run java applications in OC4J.

      Here is the stack for the error:
      Exception in thread "main" java.lang.RuntimeException: null certificates for com
      /sun/crypto/provider/DESKeyFactory.class
              at CertificateTest.checkEntry(CertificateTest.java:137)
              at CertificateTest.main(CertificateTest.java:81)

      Here is the source code to re-create the problem. An additional text file with class file name entries(testscript.txt) is required to complete the test case. I've incorporated the content at the end of this text.

      /*
       * Test Case: JarEntry.getCertificates() returns null when memory is strained.
       */
      import java.io.*;
      import java.util.*;
      import java.util.jar.*;
      import java.security.cert.Certificate;

      // This test should be run more than once, as it sometimes succeeds and
      // sometimes fails. The probability of success appears related to the
      // length of the testscript.txt input file. In general, cloning lines
      // in the middle of testscript.txt appears to increase the probability
      // of failure.
      public class CertificateTest
          {
          // Simulate heavy memory usage; the number of bytes to eat in
          // order to reproduce the failure depends on the length of the input script.
          // Adding a few thousand lines in the middle of the script will reduce
          // the required EAT_BYTES size by several orders of magnitude.
          static final boolean EAT_MEMORY = true;
          static final int EAT_BYTES = 700000;
          
          static final String INPUT_SCRIPT_FILE = "testscript.txt";
          
          private static byte[] buffer;

          public static void main(String[] args)
                  throws IOException
              {
              FileInputStream in = new FileInputStream(INPUT_SCRIPT_FILE);
              BufferedReader br = new BufferedReader(new InputStreamReader(in));

              ArrayList memoryEater = new ArrayList();
              TreeMap tmJarFiles = new TreeMap();

              int openJarCount = 0;
              int getEntryCount = 0;

              int nLine = 0;
              for (;;)
                  {
                  String sLine = br.readLine();
                  ++nLine;
      // System.out.println("Line " + nLine);
                  if (sLine == null)
                      break;
                      
                  if (sLine.startsWith("open "))
                      {
                      String sTarget = sLine.substring(5);
                      System.out.println("open [" + sTarget + "]");
                      
                      if (!tmJarFiles.containsKey(sTarget))
                          {
                          ++openJarCount;
                          JarFile jf = new JarFile(sTarget);
                          tmJarFiles.put(sTarget, jf);
                          }
                      }
                  else if (sLine.startsWith("getJarEntry "))
                      {
                      getEntryCount++;

                      if (EAT_MEMORY)
                          memoryEater.add(new byte[EAT_BYTES]);

                      int nInPos = sLine.indexOf(" in ");
                      String entryName = sLine.substring(12, nInPos);
                      String fileName = sLine.substring(nInPos + 4);
      // System.out.println("getJarEntry [" + entryName + "] from [" + fileName + "]");
                      
                      JarFile jf = (JarFile) tmJarFiles.get(fileName);
                      if (jf == null)
                          throw new RuntimeException("jar file not in list: " + fileName);

                      JarEntry entry = jf.getJarEntry(entryName);
                      if (entry == null)
                          throw new RuntimeException("didn't find entry " + entryName + " in " + jf);

                      checkEntry(jf, entry, entryName);
                      }
                  }
                  
              br.close();

              // successful outcome
              System.out.println("\n Test succeeded");
              System.out.println(" " + getEntryCount + " getJarEntry calls");
              System.out.println(" " + openJarCount + " open jars");
              }

          static void checkEntry(JarFile jar, JarEntry entry, String entryName)
                  throws IOException
              {
              Certificate[] certs = null;

              int entrySize = (int) entry.getSize();

              InputStream in = null;
              try
                  {
                  in = jar.getInputStream(entry);

                  if (buffer == null || entrySize > buffer.length)
                      buffer = new byte[entrySize];

                  int bytesUsed = 0;
                  for (int remaining = entrySize; remaining > 0; )
                      {
                      int readSize = in.read(buffer, bytesUsed, remaining);
                      if (readSize == -1)
                          throw new IOException("Unexpected EOF");
                          
                      remaining -= readSize;
                      bytesUsed += readSize;
                      }

                  certs = entry.getCertificates();
                  }
              finally
                  {
                  if (in != null)
                      in.close();
                  }

              if (certs == null)
                  {
                  // With 'memory eating' disabled we find 2 certificates for
                  // this entry. With 'memory eating' enabled, we usually get a null.
                  // Reducing the length of the input script by chopping lines out
                  // of the middle appears to increase the probability of correctly
                  // retrieving the certificates.
                  if (entryName.equals("com/sun/crypto/provider/DESKeyFactory.class"))
                      {
                      System.out.println("\n** FAILED ***\n");
                      throw new RuntimeException("null certificates for " + entry);
                      }
                  }
              }
          }

      open sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar
      getJarEntry com/sun/crypto/provider/SunJCE_al.class in sunjce_provider.jar

      getJarEntry com/sun/crypto/provider/SunJCE.class in sunjce_provider.jar


      getJarEntry com/sun/crypto/provider/DESKeyFactory.class in sunjce_provider.jar

      Release Regression From : 5.0u3
      The above release value was the last known release where this
      bug was known to work. Since then there has been a regression.
      ###@###.### 2005-07-20 17:38:29 GMT

            claisunw Charlie Lai (Inactive)
            mmma Marvin Ma (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: