JDK-6299460 : REGRESSION: JarEntry.getCertificates() returns null when memory is strained
  • Type: Bug
  • Component: security-libs
  • Sub-Component: java.security
  • Affected Version: 5.0u4
  • Priority: P5
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2005-07-20
  • Updated: 2010-04-02
  • Resolved: 2005-09-21
Related Reports
Duplicate :  
Description
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

Comments
EVALUATION it looks like this was caused as a result of: 6226269 JAR verification causes significant footprint increases and then fixed as a result of: 6283161 PIT: Standard Extension test throws ExtensionInstallationException i'll close the bug out.
21-09-2005

EVALUATION This bug may lie in the grey area between classes_util_jarzip and classes_security, but the current maintainer of classes_util_jarzip is not familiar with the security API, so it seems best to redirect it to classes_security.
25-07-2005

WORK AROUND Workaround was to move back to JDK 1.5.0_3 ###@###.### 2005-07-20 17:38:30 GMT
20-07-2005