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

ZipOutputStream.close() should always close the wrapped stream

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P4 P4
    • 23
    • core-libs
    • None
    • behavioral
    • low
    • Hide
      There is a low probability that code has evolved to depend on the underlying stream not being closed when flushing throws an IOException. It is difficult to imagine what benefits this might give an application. Any benefit should be outweighed by the benefits of fixing this potential resource leak which is hard to diagnose and reproduce.

      There is a low probability that code has evolved to depend on the underlying stream being closed more than once. It is worth noting that the finish() operation itself is never executed more than once, so it is unclear how an application could take advantage of this behavior.
      Show
      There is a low probability that code has evolved to depend on the underlying stream not being closed when flushing throws an IOException. It is difficult to imagine what benefits this might give an application. Any benefit should be outweighed by the benefits of fixing this potential resource leak which is hard to diagnose and reproduce. There is a low probability that code has evolved to depend on the underlying stream being closed more than once. It is worth noting that the finish() operation itself is never executed more than once, so it is unclear how an application could take advantage of this behavior.
    • Java API
    • Implementation

      Summary

      Update java.util.zip.DeflaterOutputStream to close the wrapped stream exactly once, even in cases where the wrapped stream throws an IOException while flushing remaining deflated data.

      This brings the method in line with its specification, and also with the specification of the overridden method FilterOutputStream.close().

      Problem

      Problem A: The wrapped stream may not be closed

      DeflaterOutputStream.close is specified as "Writes remaining compressed data to the output stream and closes the underlying stream".

      However, the current implementation does not always close the underlying ("wrapped") stream, specifically in the case where the wrapped stream throws an IOException when data remaining in the Deflator is flushed in DeflaterOutputStream.finish().

      This may cause unintended leaks of resources such as file desciptors and network sockets.

      Problem B: The wrapped stream may be closed more than once

      The @implSpec in FilterOutputStream.close specifies that flushing of buffers and closing of the wrapped stream should only happen once: "When not already closed, the close method of FilterOutputStream calls its flush method, and then calls the close method of its underlying output stream".

      However, the current implementation does not update the boolean "closed" flag to true if an IOException is thrown during flushing.

      This may cause that the wrapped stream to be closed more than once and Deflator.end() to be called more than once.

      Solution

      Update DeflaterOutputStream.close to:

      • Move the setting of closed = true from the end of the if(!closed) block to the beginning of the block, ensuring that a close will only ever be attempted once.
      • Catch, capture to a local variable and rethrow any IOException during the call to finish()
      • In the finally block, check whether finish() did throw an IOException
      • If finish did throw: Close the wrapped stream in a try/catch where the catch adds the IOException from the call to finish() as a suppressed exception of the IOException which happened during close. (If the two exceptions have the same identity, avoid adding the exception as suppressed on itself)
      • If finish did not throw: Simply close the wrapped stream, letting any IOException propagate out of DeflaterInputStream.close.

      A new test is added to cover a variation of failure mode combinations, verifying the invariant that the wrapped stream is closed exactly once.

      Specification

      This is strictly an implementation change. The specification is not changed.

            eirbjo Eirik Bjørsnøs
            webbuggrp Webbug Group
            Alan Bateman, Jaikiran Pai
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: