JDK-4764778 : Interrupted thread can't load classes from classes directory (sol)
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.3.0,1.4.0,1.4.2,1.4.2_05
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS:
    generic,solaris_7,solaris_8,windows_nt generic,solaris_7,solaris_8,windows_nt
  • CPU: x86,sparc
  • Submitted: 2002-10-17
  • Updated: 2006-04-05
  • Resolved: 2006-02-04
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6
6 b71Fixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
It is important to note that this program only fails on
internal builds that don't have images made. If you have made
images, then it works. I assume that if one includes classes of
their own not in a jar, then maybe they can't load their classes
if the thread is interrupted...

import java.nio.channels.*;

public class Blah {
    public static void main(String[] args) throws Exception {
        Thread.currentThread().interrupt();
        SocketChannel.open().close(); // Any class not yet loaded
    }
}

/export/mantis> /export/cache1/build/solaris-sparc/bin/java Blah
Exception in thread "main" java.lang.NoClassDefFoundError: java/nio/channels/SocketChannel
        at Blah.main(Blah.java:6)

This bug has been present for several years.

Comments
EVALUATION The following is perhaps the canonical minimal ThreadPool test: ---------------------------------------------------------- import java.util.concurrent.*; public class Bug2 { public static void main(String[] args) throws Throwable { ExecutorService es = Executors.newFixedThreadPool(10); for (int i = 0; i < 10; i++) es.submit(new Runnable() { public void run() {}}); es.shutdown(); } } ---------------------------------------------------------- This test has serious reliability problems when run on Solaris with mustang b51 (there may be more than one bug at hand here) When run repeatedly, it may succeed, or hang, or give: Exception in thread "pool-1-thread-1" java.lang.InterruptedException at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:705) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:735) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1067) at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:187) at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:263) at java.util.concurrent.ThreadPoolExecutor.workerDone(ThreadPoolExecutor.java:551) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:698) at java.lang.Thread.run(Thread.java:611) or java.lang.NoClassDefFoundError: Lsun/nio/ch/Interruptible; at java.lang.Class.getDeclaredFields0(Native Method) at java.lang.Class.privateGetDeclaredFields(Class.java:2243) at java.lang.Class.getDeclaredField(Class.java:1863) at java.util.concurrent.locks.LockSupport.<clinit>(LockSupport.java:95) at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:705) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:735) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1067) at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:187) at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:263) at java.util.concurrent.ThreadPoolExecutor.interruptIdleWorkers(ThreadPoolExecutor.java:536) at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:512) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:693) at java.lang.Thread.run(Thread.java:611)
11-09-2005

SUGGESTED FIX Doug Lea suggests this fix: --- /tmp/geta4152 2005-09-11 08:06:55.327050800 -0700 +++ Resource.java 2005-09-11 08:05:16.613513000 -0700 @@ -5,27 +5,28 @@ * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package sun.misc; import java.net.URL; import java.io.IOException; +import java.io.InterruptedIOException; import java.io.InputStream; import java.security.CodeSigner; import java.util.jar.Manifest; import java.util.jar.Attributes; import java.nio.ByteBuffer; import sun.nio.ByteBuffered; /** * This class is used to represent a Resource that has been loaded * from the class path. * * @author David Connelly - * @version %I%, %G% + * @version 1.15, 12/19/03 * @since JDK1.2 */ public abstract class Resource { /** * Returns the name of the Resource. */ public abstract String getName(); @@ -64,47 +65,86 @@ * Returns the Resource data as an array of bytes. */ public byte[] getBytes() throws IOException { byte[] b; // Get stream before content length so that a FileNotFoundException // can propagate upwards without being caught too early InputStream in = cachedInputStream(); - int len = getContentLength(); - try { - if (len != -1) { - // Read exactly len bytes from the input stream - b = new byte[len]; - while (len > 0) { - int n = in.read(b, b.length - len, len); - if (n == -1) { - throw new IOException("unexpected EOF"); - } - len -= n; - } - } else { - // Read until end of stream is reached - b = new byte[1024]; - int total = 0; - while ((len = in.read(b, total, b.length - total)) != -1) { - total += len; - if (total >= b.length) { - byte[] tmp = new byte[total * 2]; - System.arraycopy(b, 0, tmp, 0, total); - b = tmp; - } - } - // Trim array to correct size, if necessary - if (total != b.length) { - byte[] tmp = new byte[total]; - System.arraycopy(b, 0, tmp, 0, total); - b = tmp; - } - } + + // This code has been uglified to protect against interrupts. + // Even if a thread has been interrupted when loading resources, + // the IO should not abort, so must carefully retry, failing only + // if the retry leads to some other IO exception + boolean isInterrupted = Thread.interrupted(); + int len; + for (;;) { + try { + len = getContentLength(); + break; + } catch(InterruptedIOException iioe) { + Thread.interrupted(); + isInterrupted = true; + } + } + + try { + if (len != -1) { + // Read exactly len bytes from the input stream + b = new byte[len]; + while (len > 0) { + int n = 0; + try { + n = in.read(b, b.length - len, len); + } catch(InterruptedIOException iioe) { + Thread.interrupted(); + isInterrupted = true; + } + if (n == -1) { + throw new IOException("unexpected EOF"); + } + len -= n; + } + } else { + // Read until end of stream is reached + b = new byte[1024]; + int total = 0; + for (;;) { + len = 0; + try { + len = in.read(b, total, b.length - total); + if (len == -1) + break; + } catch(InterruptedIOException iioe) { + Thread.interrupted(); + isInterrupted = true; + } + total += len; + if (total >= b.length) { + byte[] tmp = new byte[total * 2]; + System.arraycopy(b, 0, tmp, 0, total); + b = tmp; + } + } + // Trim array to correct size, if necessary + if (total != b.length) { + byte[] tmp = new byte[total]; + System.arraycopy(b, 0, tmp, 0, total); + b = tmp; + } + } } finally { - in.close(); + try { + in.close(); + } catch(InterruptedIOException iioe) { + isInterrupted = true; + } catch(IOException ignore) {} + + if (isInterrupted) { + Thread.currentThread().interrupt(); + } } return b; } /** * Returns the Resource data as a ByteBuffer, but only if the input stream * was implemented on top of a ByteBuffer. Return <tt>null</tt> otherwise.
11-09-2005

EVALUATION I suspect that some activity involved in class loading/intialization (probably IO) is failing with an InterruptedException, which is silently translated to a NoClassDefFoundError. This is clearly a bug and should be fixed. ###@###.### 2003-01-14 This is also a problem if the class being searched for is on the user class path instead of the bootclasspath. See the shell transcript below: ------------------------------------------------------------------ $ cat Bug.java public class Bug { public static void main(String[] args) { class Empty {} Thread.currentThread().interrupt(); new Empty(); } } $ jver 6.0 jr Bug ==> javac -source 1.6 -Xlint:all Bug.java ==> java -esa -ea Bug Exception in thread "main" java.lang.NoClassDefFoundError: Bug$1Empty at Bug.main(Bug.java:5) Command java -esa -ea Bug failed: rc=1 ------------------------------------------------------------------ so this may be a rather more important bug to fix. ###@###.### 2004-01-24
24-01-2004

SUGGESTED FIX It may be necessary to clear the interrupted status, load teh class, and reinterrupt the current thread. ###@###.### 2003-01-14
14-01-2003