-
Bug
-
Resolution: Fixed
-
P4
-
1.3.1, 1.3.1_03
-
05
-
generic, sparc
-
generic, solaris_8
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-2056139 | 1.4.2 | Andreas Sterbenz | P4 | Resolved | Fixed | mantis |
JDK-2056138 | 1.4.1_02 | Andreas Sterbenz | P4 | Resolved | Fixed | 02 |
JDK-2056137 | 1.4.0_03 | Andreas Sterbenz | P4 | Resolved | Fixed | 03 |
Name: dk106046 Date: 07/01/2002
The primordial and standard extension class loader sun.misc.Launcher$ExtClassLoader are both trying to lock themselves then the other simultaneously, leaving two threads deadlocked, both with one loader locked and waiting on the other. The problem is present on all platforms in 1.3.1 and 1.4.x.
Details of the problem:
Thread "P=886672:O=0:LT=0:port=4582" (TID:0x9016D0, sys_thread_t:0x436F4098, state:CW, native ID:0x2BC) prio=5
Owns sun.misc.Launcher$AppClassLoader@901830/901838
Blocked on sun.misc.Launcher$ExtClassLoader@901898/9018A0
Thread "P=886672:O=0:CT" (TID:0x9019D8, sys_thread_t:0x7B9040, state:CW, native ID:0xA6C) prio=5
Owns sun.misc.Launcher$ExtClassLoader@901898/9018A0
Blocked on sun.misc.Launcher$AppClassLoader@901830/901838
The first thread is following normal locking order for classloaders: Application->Extension->Primordial
The second thread is attempting to get a lock in the reverse direction, and therefore is causing a deadlock.
The second thread has the following stack trace:
"P=886672:O=0:CT" (TID:0x9019D8, sys_thread_t:0x7B9040, state:CW, native ID:0xA6C) prio=5
at java.lang.ClassLoader.loadClass(ClassLoader.java:445)
at sun.security.x509.OIDMap$1.run(OIDMap.java:272)
at java.security.AccessController.doPrivileged(Native Method)
at sun.security.x509.OIDMap.loadOidClass(OIDMap.java:269)
at sun.security.x509.OIDMap.getClass(OIDMap.java:252)
at sun.security.x509.CertificateExtensions.parseExtension(CertificateExtensions.java:101)
at sun.security.x509.CertificateExtensions.init(CertificateExtensions.java:94)
at sun.security.x509.CertificateExtensions.<init>(CertificateExtensions.java:73)
at sun.security.x509.X509CertInfo.parse(X509CertInfo.java:732)
Here OIDMap.loadOidClass() explicitly requests the Application call loader using getSystemClassLoader(), and procedes to try to load the class with this class loader.
Solution:
The simple solution is to force OIDMap.loadOidClass() to load the class with the current class loader using Class.forName(), which is currently the default should getSystemClassLoader() fail to return a class loader.
We have modified OIDMap.java as follows:
private static Class loadOidClass(String className)
throws ClassNotFoundException
{
Class extClass = null;
final String clName = className;
/*final ClassLoader loader = ClassLoader.getSystemClassLoader();
if (loader != null) {
tr y {
extClass = (Class)AccessController.doPrivileged
(new PrivilegedExceptionAction() {
public Object run() throws ClassNotFoundException {
return loader.loadClass(clName);
}
});
} catch (PrivilegedActionException pae) {
throw (ClassNotFoundException) pae.getException();
}
} else {*/
extClass = Class.forName(clName);
//}
return extClass;
}
Testcase to demonstrate the deadlock (further jar files are also required, which are available on request):
import java.util.*;
import java.util.jar.*;
import java.net.*;
import java.io.*;
public class CLLockup
{
public static void main (String[] args)
{
Vector v = new Vector ();
// add jdk jars
addJarFiles (System.getProperty ("java.home") + File.separator + "lib", v);
Thread thrd = new Thread (new CLThread (v, null));
thrd.start ();
// get a random delay within 1/2 sec
int delay = Math.abs (new java.util.Random ().nextInt () % 500);
// sleep for delay
try {
Thread.sleep (delay);
} catch (InterruptedException ie) {}
// get default factory
Object o = javax.net.ssl.SSLServerSocketFactory.getDefault ();
System.out.println ("DF " + o + " loaded by " + o.getClass ().getClassLoader ());
try
{
// wait for the thread to end
thrd.join ();
} catch (InterruptedException ie) {}
System.exit (0);
}
private static class CLThread implements Runnable
{
private URLClassLoader _ucl;
private Vector _v;
private CLThread (Vector v, URLClassLoader ucl)
{
Vector urls = new Vector ();
for (int i=0; i<v.size (); i++)
try {
urls.addElement (((File)v.elementAt (i)).toURL ());
} catch (Exception e)
{
e.printStackTrace ();
}
// create URL class loader
ucl = new URLClassLoader ((URL[])urls.toArray (new URL [urls.size ()]));
this._ucl = ucl;
this._v = v;
}
public void run ()
{
for (int i=0; i<_v.size (); i++)
{
int nLoaded = 0, errors = 0;
JarFile jf = null;
try
{
jf = new JarFile ((File)_v.elementAt (i));
Enumeration e = jf.entries ();
while (e.hasMoreElements ())
{
String name = ((JarEntry)e.nextElement ()).getName ();
if (name.endsWith (".class") && name.indexOf (":") == -1)
{
String className = name.substring (0, name.length () - 6);
className = className.replace ('/', '.');
try {
// now load this class
_ucl.loadClass (className);
// Class.forName (className);
nLoaded++;
} catch (Throwable t)
{
// t.printStackTrace ();
errors++;
}
}
}
System.out.println (jf.getName () + " : loaded " + nLoaded + " errors " + errors);
} catch (Exception e)
{
e.printStackTrace ();
}
}
}
}
private static void addJarFiles (String path, Vector v)
{
if (path == null || path.length () == 0 || v == null)
throw new IllegalArgumentException ("bad arg(s) to addJarFiles ()");
File dir = new File (path);
if (dir.exists () && dir.isDirectory ())
{
File[] f = dir.listFiles ();
for (int i=0; i<f.length; i++)
{
if (f [i].exists () && !f [i].isDirectory () && f [i].getPath ().toLowerCase ().endsWith (".jar"))
// is a jar file. add it
v.addElement (f [i]);
}
}
}
}
======================================================================
- backported by
-
JDK-2056137 ClassLoader deadlock in OIDMap.java
-
- Resolved
-
-
JDK-2056138 ClassLoader deadlock in OIDMap.java
-
- Resolved
-
-
JDK-2056139 ClassLoader deadlock in OIDMap.java
-
- Resolved
-
- duplicates
-
JDK-5019612 Detecting the following deadlock during thread dumps involving class loader
-
- Closed
-
- relates to
-
JDK-5015761 deadlock during classloading: Introspector.instantiate() getSystemClassLoader()
-
- Closed
-