JDK-6429910 : (fc) FileChannel.lock() IOException: Bad file number, not AsynchronousCloseException
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 1.4.2
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: solaris_8
  • CPU: sparc
  • Submitted: 2006-05-24
  • Updated: 2013-07-08
  • Resolved: 2009-04-25
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 JDK 7
6u71Fixed 7 b57Fixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
Both:

Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_02-b03)
Java HotSpot(TM) Client VM (build 1.4.2_02-b03, mixed mode)

Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_02-b06)
Java HotSpot(TM) Client VM (build 1.4.1_02-b06, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
SunOS goldtpus7 5.8 Generic_108528-23 sun4u sparc SUNW,Sun-Fire-280R

A DESCRIPTION OF THE PROBLEM :
Coding timeout for FileChannel.lock() by closing the channel from a timer thread. Get

java.io.IOException: Bad file number
        at sun.nio.ch.FileChannelImpl.lock0(Native Method)
        at sun.nio.ch.FileChannelImpl.lock(FileChannelImpl.java:750)
        at java.nio.channels.FileChannel.lock(FileChannel.java:865)

Instead of AsynchronousCloseException

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the applied test.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
test passed
ACTUAL -
test failed: wrong exception class
java.io.IOException: Bad file number
        at sun.nio.ch.FileChannelImpl.lock0(Native Method)
        at sun.nio.ch.FileChannelImpl.lock(FileChannelImpl.java:750)
        at java.nio.channels.FileChannel.lock(FileChannel.java:865)
        at Simul$Waiter.run(Simul.java:14)
        at java.lang.Thread.run(Thread.java:534)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.io.*;
import java.nio.channels.*;

public class Simul
{
    static FileChannel m_channel;

    static class Waiter implements Runnable
    {
        public void run()
        {
            try
            {
                m_channel.lock();
            }
            catch( AsynchronousCloseException ace )
            {
                System.out.println( "test passed" );
                return;
            }
            catch( IOException ioe )
            {
                System.out.println( "test failed: wrong exception class" );
                ioe.printStackTrace();
                return;
            }
            System.out.println( "test failed\nwe were blocked until " +
                    "the other jvm released the lock\n" +
                    "are we on windows? this test was for Solaris!" );
        }
    }
    public static void main( final String[] args )
    {
        try
        {
            if ( args.length > 0 )
            {
                /* we just lock the file for 5 seconds */
                final FileOutputStream fos = new FileOutputStream( args[0] );
                final FileChannel channel = fos.getChannel();
                channel.lock();
                Thread.sleep( 5000l );
            }
            else
            {
                final File currDir = new File( "." );
                final File playFile =
                        File.createTempFile( "aaa_", ".txt", currDir );

                final String playPath = playFile.getCanonicalPath();
                final Runtime runtime = Runtime.getRuntime();
                final String execArgs[] = new String[]
                {
                    "java",
                    "-cp",
                    ".",
                    Simul.class.getName(),
                    playPath,
                };

                final Process me2 = runtime.exec( execArgs );

                /* give the other jvm time to start up */
                Thread.sleep( 1000l );
                try
                {
                    me2.exitValue();
                    System.out.println( "failed to launch second jvm" );
                }
                catch( IllegalThreadStateException itse )
                {
                    final FileOutputStream fos = new FileOutputStream( playFile );
                    m_channel = fos.getChannel();
                    final Runnable waiter = new Waiter();
                    final Thread t = new Thread( waiter, "waiter" );
                    t.start();
                    /* give the waiter time to start */
                    Thread.sleep( 500l );
                    fos.close();
                    m_channel.close();
                }
            }
        }
        catch( Throwable t )
        {
            t.printStackTrace();
        }
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Catch IOException
and treat it as
AsynchronousCloseException

Comments
SUGGESTED FIX diff -r 60cca22e8d57 src/share/classes/sun/nio/ch/FileChannelImpl.java --- a/src/share/classes/sun/nio/ch/FileChannelImpl.java Sun Mar 08 17:14:58 2009 +0000 +++ b/src/share/classes/sun/nio/ch/FileChannelImpl.java Mon Mar 09 17:06:20 2009 +0000 @@ -899,23 +899,26 @@ public class FileChannelImpl FileLockImpl fli = new FileLockImpl(this, position, size, shared); FileLockTable flt = fileLockTable(); flt.add(fli); - boolean i = true; + boolean completed = false; int ti = threads.add(); try { begin(); if (!isOpen()) return null; int result = nd.lock(fd, true, position, size, shared); - if (result == FileDispatcher.RET_EX_LOCK) { + if (result == FileDispatcher.LOCKED) { + completed = true; + } else if (result == FileDispatcher.RET_EX_LOCK) { assert shared; FileLockImpl fli2 = new FileLockImpl(this, position, size, false); flt.replace(fli, fli2); - return fli2; - } - if (result == FileDispatcher.INTERRUPTED || result == FileDispatcher.NO_LOCK) { + fli = fli2; + completed = true; + } else if (result == FileDispatcher.INTERRUPTED) { flt.remove(fli); - i = false; + } else { + throw new InternalError(); } } catch (IOException e) { flt.remove(fli); @@ -923,7 +926,7 @@ public class FileChannelImpl } finally { threads.remove(ti); try { - end(i); + end(completed); } catch (ClosedByInterruptException e) { throw new FileLockInterruptionException(); }
09-03-2009

EVALUATION Yes, we need to handle this case and throw AsynchronousCloseException as specified. The bug arrived too late for Mustang so we have to defer it to Dolphin.
24-05-2006