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

BufferedOutputStream.close does not throw IOException on error

    XMLWordPrintable

Details

    • Bug
    • Resolution: Duplicate
    • P4
    • None
    • 6u29
    • core-libs
    • x86
    • linux

    Description

      FULL PRODUCT VERSION :
      java version "1.6.0_29"
      Java(TM) SE Runtime Environment (build 1.6.0_29-b11)
      Java HotSpot(TM) 64-Bit Server VM (build 20.4-b02, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      Linux X 2.6.5-7.319-smp #1 SMP Mon Aug 24 10:05:14 UTC 2009 x86_64 x86_64 x86_64 GNU/Linux

      A DESCRIPTION OF THE PROBLEM :
      If an I/O error, e.g. disk full,, occurs during close on a BufferedOutputStream, the error will go unnoticed.

      close does attempt to flush the buffer, but it swallows an error and then closes the underlying stream.

      It should probably still try to close the underlying stream, but exception from flush
      should be re-thrown.

      Few, if any, programs call flush on streams to close them.

      Usually a program will report and error if th disk becomes full, but if will not tell the user that a file might have been corrupted before the point of error.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Extract the following two files on a Linux machine and run the shell
      script.

      ==BEGIN Fill.java
      #!/bin/sh -e
      # Linux script requiring.User may want to change mount point and/or loop device
      here=$(pwd)
      export CLASSPATH=$(pwd)
      MOUNTPOINT=/mnt/almostfull
      DEVICE=/dev/loop0
      umount $MOUNTPOINT || true
      /sbin/losetup -d $DEVICE || true

      dd if=/dev/zero of=mydevice.dsk bs=512 count=1024
      /sbin/losetup $DEVICE mydevice.dsk
      /sbin/mkfs.ext2 $DEVICE
      mkdir -p $MOUNTPOINT
      mount $DEVICE $MOUNTPOINT
      javac Fill.java
      pushd $MOUNTPOINT
      touch empty
      if dd if=/dev/zero of=filler.dat bs=1
      then
          : We fill the disk, so it becomes full
          echo internal error
          exit 1
      fi
      rm empty
      if java Fill -fail
      then
          : # explicit flush, should fail
          echo internal error
          exit 1
      fi

      java Fill
      echo Should not get here. Program failed to write file

      popd
      set +e
      umount $MOUNTPOINT || true
      /sbin/losetup -d $DEVICE || true

      END demo.sh



      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      sudo bash -x -e ./x.sh
      ++ pwd
      + here=/home/roro/tmp
      ++ pwd
      + export CLASSPATH=/home/roro/tmp
      + CLASSPATH=/home/roro/tmp
      + MOUNTPOINT=/mnt/almostfull
      + DEVICE=/dev/loop0
      + umount /mnt/almostfull
      umount: /mnt/almostfull: not mounted
      + true
      + /sbin/losetup -d /dev/loop0
      ioctl: LOOP_CLR_FD: No such device or address
      + true
      + dd if=/dev/zero of=mydevice.dsk bs=512 count=1024
      1024+0 records in
      1024+0 records out
      + /sbin/losetup /dev/loop0 mydevice.dsk
      + /sbin/mkfs.ext2 /dev/loop0
      mke2fs 1.38 (30-Jun-2005)
      Filesystem label=
      OS type: Linux
      Block size=1024 (log=0)
      Fragment size=1024 (log=0)
      64 inodes, 512 blocks
      25 blocks (4.88%) reserved for the super user
      First data block=1
      1 block group
      8192 blocks per group, 8192 fragments per group
      64 inodes per group

      Writing inode tables: done
      Writing superblocks and filesystem accounting information: done

      This filesystem will be automatically checked every 32 mounts or
      180 days, whichever comes first. Use tune2fs -c or -i to override.
      + mkdir -p /mnt/almostfull
      + mount /dev/loop0 /mnt/almostfull
      + javac Fill.java
      + pushd /mnt/almostfull
      /mnt/almostfull ~/tmp
      + touch empty
      + dd if=/dev/zero of=filler.dat bs=1
      dd: writing `filler.dat': No space left on device
      494593+0 records in
      494592+0 records out
      + rm empty
      + java Fill -fail
      Exception in thread "main" java.io.IOException: No space left on device
      at java.io.FileOutputStream.writeBytes(Native Method)
      at java.io.FileOutputStream.write(FileOutputStream.java:282)
      at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
      at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
      at Fill.main(Fill.java:8)
      + java Fill
      Exception in thread "main" java.io.IOException: No space left on device
      at java.io.FileOutputStream.writeBytes(Native Method)
      at java.io.FileOutputStream.write(FileOutputStream.java:282)
      at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
      at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
      at Fill.main(Fill.java:8)

      # i.e. both invocations of Fill should fail

      ACTUAL -
      sudo bash -x -e ./x.sh
      ++ pwd
      + here=/home/roro/tmp
      ++ pwd
      + export CLASSPATH=/home/roro/tmp
      + CLASSPATH=/home/roro/tmp
      + MOUNTPOINT=/mnt/almostfull
      + DEVICE=/dev/loop0
      + umount /mnt/almostfull
      umount: /mnt/almostfull: not mounted
      + true
      + /sbin/losetup -d /dev/loop0
      ioctl: LOOP_CLR_FD: No such device or address
      + true
      + dd if=/dev/zero of=mydevice.dsk bs=512 count=1024
      1024+0 records in
      1024+0 records out
      + /sbin/losetup /dev/loop0 mydevice.dsk
      + /sbin/mkfs.ext2 /dev/loop0
      mke2fs 1.38 (30-Jun-2005)
      Filesystem label=
      OS type: Linux
      Block size=1024 (log=0)
      Fragment size=1024 (log=0)
      64 inodes, 512 blocks
      25 blocks (4.88%) reserved for the super user
      First data block=1
      1 block group
      8192 blocks per group, 8192 fragments per group
      64 inodes per group

      Writing inode tables: done
      Writing superblocks and filesystem accounting information: done

      This filesystem will be automatically checked every 32 mounts or
      180 days, whichever comes first. Use tune2fs -c or -i to override.
      + mkdir -p /mnt/almostfull
      + mount /dev/loop0 /mnt/almostfull
      + javac Fill.java
      + pushd /mnt/almostfull
      /mnt/almostfull ~/tmp
      + touch empty
      + dd if=/dev/zero of=filler.dat bs=1
      dd: writing `filler.dat': No space left on device
      494593+0 records in
      494592+0 records out
      + rm empty
      + java Fill -fail
      Exception in thread "main" java.io.IOException: No space left on device
      at java.io.FileOutputStream.writeBytes(Native Method)
      at java.io.FileOutputStream.write(FileOutputStream.java:282)
      at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
      at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
      at Fill.main(Fill.java:8)
      + java Fill
      + echo Should not get here. Program failed to write file
      Should not get here. Program failed to write file
      + popd
      ~/tmp
      + set +e
      + umount /mnt/almostfull
      + /sbin/losetup -d /dev/loop0

      # i.e. the program that only uses close() does not report an error


      REPRODUCIBILITY :
      This bug can be reproduced always.

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

      public class Fill {
          public static void main(String[] args) throws IOException {
              BufferedOutputStream b = new BufferedOutputStream(new FileOutputStream("full"));
              b.write("data".getBytes());
              if (args.length > 0)
                  b.flush();
              b.close();
          }
      }


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

      CUSTOMER SUBMITTED WORKAROUND :
      alway call flush before close

      Attachments

        Issue Links

          Activity

            People

              Unassigned Unassigned
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: