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

FilterOutputStream.close may throw IOException if called twice and underlying flush or close fails

    Details

    • Subcomponent:
    • Resolved In Build:
      b46
    • Verification:
      Verified

      Backports

        Description

        FULL PRODUCT VERSION :


        A DESCRIPTION OF THE PROBLEM :
        The change for Bug ID 7015589 included a change to FilterOutputStream so that it does not swallow exceptions when calling flush:

        http://hg.openjdk.java.net/hsx/hotspot-rt/jdk/rev/759aa847dcaf

             public void close() throws IOException {
                try (OutputStream ostream = out) {
                    flush();
                 }
             }

        The problem is that if close() is called a second time, flush() will be called on the underlying stream after it has already been closed. Many underlying streams will throw an exception in this case.

        The implementation of FilterOutputStream.close() should be changed so that it follows the contract of Closeable:

        "Closes this stream and releases any system resources associated with it. If the stream is already closed then invoking this method has no effect."

        One possible implementation idea is to introduce a member variable to track whether the stream has already been closed:

            public void close() throws IOException {
                if (!closed) {
                 closed = true;
                    try (OutputStream ostream = out) {
                        flush();
                    }
                }
            }

        See http://stackoverflow.com/questions/25175882/java-8-filteroutputstream-exception/

        REGRESSION. Last worked in version 7u67

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Run the attached test program

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        No exception is thrown
        ACTUAL -
        Exception is thrown:

        Exception in thread "main" java.io.IOException: Stream closed
        at FilterOutputStreamTest$MockBlobOutputStream.flush(FilterOutputStreamTest.java:24)
        at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:141)
        at java.io.FilterOutputStream.close(FilterOutputStream.java:158)
        at FilterOutputStreamTest.main(FilterOutputStreamTest.java:52)



        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        import java.io.BufferedOutputStream;
        import java.io.ByteArrayInputStream;
        import java.io.ByteArrayOutputStream;
        import java.io.IOException;
        import java.io.InputStream;
        import java.io.OutputStream;
        import java.util.zip.Deflater;
        import java.util.zip.DeflaterOutputStream;

        public class FilterOutputStreamTest
        {
            /**
             * This stream simulates a OracleBlobOutputStream which will throw
             * an exception if flush is called after close.
             */
            static class MockBlobOutputStream extends ByteArrayOutputStream
            {
                private boolean closed;

                @Override
                public void flush() throws IOException
                {
                    if (closed) {
                        throw new IOException("Stream closed");
                    }
                }

                @Override
                public void close() throws IOException
                {
                    closed = true;
                }
            }

            public static void main( final String[] args ) throws Exception
            {
                try( InputStream bis = new ByteArrayInputStream( "Hello".getBytes() );
                     OutputStream outStream = new MockBlobOutputStream();
                     BufferedOutputStream bos = new BufferedOutputStream( outStream );
                     DeflaterOutputStream deflaterStream = new DeflaterOutputStream(
                         bos, new Deflater( 3 ) ) )
                {
                    int len = 0;
                    final byte[] buf = new byte[1024];
                    while ((len = bis.read(buf)) >= 0)
                    {
                        if ( len > 0 )
                        {
                            deflaterStream.write(buf,0,len);
                        }
                    }
                }
            }
        }
        ---------- END SOURCE ----------

          Attachments

            Issue Links

              Activity

                People

                • Assignee:
                  chegar Chris Hegarty
                  Reporter:
                  webbuggrp Webbug Group
                • Votes:
                  0 Vote for this issue
                  Watchers:
                  4 Start watching this issue

                  Dates

                  • Created:
                    Updated:
                    Resolved: