[patch, libfortran] Fix PR 30009 and 30056

Thomas Koenig Thomas.Koenig@online.de
Tue Dec 5 18:59:00 GMT 2006


:ADDPATCH fortran:

Hello world,

here is a patch for PR 30009.  Regression-tested on i686-pc-linux-gnu
by myself, also tested by Jerry DeLisle (in a version that was
only different in whitespace and comments).

OK for mainline and 4.2 (after the subrecord patch has gone
into 4.2)?

For fixing this in 4.1, a different patch will be necessary.  I'll
do submit this separately.

	Thomas

2006-12-05  Thomas Koenig  <Thomas.Koenig@online.de>

	PR libfortran/30009
	PR libfortran/30056
	* gfortran.dg/read_eof_4.f90:  Add tests.
	* gfortran.dg/readwrite_unf_direct_eor_1.f90:  New test.
	* gfortran.dg/unf_read_corrupted_1.f90: New test.

2006-12-05  Thomas Koenig  <Thomas.Koenig@online.de>

	PR libfortran/30009
	PR libfortran/30056
	* libgfortran.h:  Add ERROR_CORRUPT_FILE to error_codes.
	* runtime/error.c (translate_error):  Add handling for
	ERROR_CORRUPT_FILE.
	* io/transfer.c (read_block_direct):  Add comment about
	EOR for stream files.
	Remove test for no bytes left for direct access files.
	Generate an ERROR_SHORT_RECORD if the read was short.
	For unformatted sequential files:  Check endfile condition.
	Remove test for no bytes left.  End of file here means
	that the file structure has been corrupted.  Pre-position
	the file for the next record in case of error.
	(write_buf):  Whitespace fix.  Subtract the number of bytes
	written from bytes_left.
-------------- next part --------------
Index: libgfortran/runtime/error.c
===================================================================
--- libgfortran/runtime/error.c	(revision 119412)
+++ libgfortran/runtime/error.c	(working copy)
@@ -440,6 +440,10 @@ translate_error (int code)
       p = "I/O past end of record on unformatted file";
       break;
 
+    case ERROR_CORRUPT_FILE:
+      p = "Unformatted file structure has been corrupted";
+      break;
+
     default:
       p = "Unknown error code";
       break;
Index: libgfortran/libgfortran.h
===================================================================
--- libgfortran/libgfortran.h	(revision 119412)
+++ libgfortran/libgfortran.h	(working copy)
@@ -416,6 +416,7 @@ typedef enum
   ERROR_ALLOCATION,
   ERROR_DIRECT_EOR,
   ERROR_SHORT_RECORD,
+  ERROR_CORRUPT_FILE,
   ERROR_LAST			/* Not a real error, the last error # + 1.  */
 }
 error_codes;
Index: libgfortran/io/transfer.c
===================================================================
--- libgfortran/io/transfer.c	(revision 119412)
+++ libgfortran/io/transfer.c	(working copy)
@@ -374,7 +374,8 @@ read_block_direct (st_parameter_dt *dtp,
 
       if (to_read_record != have_read_record)
 	{
-	  /* Short read,  e.g. if we hit EOF.  */
+	  /* Short read,  e.g. if we hit EOF.  For stream files,
+	   we have to set the end-of-file condition.  */
 	  generate_error (&dtp->common, ERROR_END, NULL);
 	  return;
 	}
@@ -388,13 +389,6 @@ read_block_direct (st_parameter_dt *dtp,
 	  short_record = 1;
 	  to_read_record = (size_t) dtp->u.p.current_unit->bytes_left;
 	  *nbytes = to_read_record;
-
-	  if (dtp->u.p.current_unit->bytes_left == 0)
-	    {
-	      dtp->u.p.current_unit->endfile = AT_ENDFILE;
-	      generate_error (&dtp->common, ERROR_END, NULL);
-	      return;
-	    }
 	}
 
       else
@@ -411,10 +405,12 @@ read_block_direct (st_parameter_dt *dtp,
 	  return;
 	}
 
-      if (to_read_record != *nbytes)  /* Short read, e.g. if we hit EOF.  */
+      if (to_read_record != *nbytes)  
 	{
+	  /* Short read, e.g. if we hit EOF.  Apparently, we read
+	   more than was written to the last record.  */
 	  *nbytes = to_read_record;
-	  generate_error (&dtp->common, ERROR_END, NULL);
+	  generate_error (&dtp->common, ERROR_SHORT_RECORD, NULL);
 	  return;
 	}
 
@@ -430,6 +426,12 @@ read_block_direct (st_parameter_dt *dtp,
      until the request has been fulfilled or the record has run out
      of continuation subrecords.  */
 
+  if (dtp->u.p.current_unit->endfile == AT_ENDFILE)
+    {
+      generate_error (&dtp->common, ERROR_END, NULL);
+      return;
+    }
+
   /* Check whether we exceed the total record length.  */
 
   if (dtp->u.p.current_unit->flags.has_recl)
@@ -453,25 +455,7 @@ read_block_direct (st_parameter_dt *dtp,
 	{
 	  to_read_subrecord = (size_t) dtp->u.p.current_unit->bytes_left_subrecord;
 	  to_read_record -= to_read_subrecord;
-
-	  if (dtp->u.p.current_unit->bytes_left_subrecord == 0)
-	    {
-	      if (dtp->u.p.current_unit->continued)
-		{
-		  /* Skip to the next subrecord */
-		  next_record_r_unf (dtp, 0);
-		  us_read (dtp, 1);
-		  continue;
-		}
-	      else
-		{
-		  dtp->u.p.current_unit->endfile = AT_ENDFILE;
-		  generate_error (&dtp->common, ERROR_END, NULL);
-		  return;
-		}
-	    }
 	}
-
       else
 	{
 	  to_read_subrecord = to_read_record;
@@ -490,11 +474,15 @@ read_block_direct (st_parameter_dt *dtp,
 
       have_read_record += have_read_subrecord;
 
-      if (to_read_subrecord != have_read_subrecord)  /* Short read,
-							e.g. if we hit EOF.  */
+      if (to_read_subrecord != have_read_subrecord)  
+			
 	{
+	  /* Short read, e.g. if we hit EOF.  This means the record
+	     structure has been corrupted, or the trailing record
+	     marker would still be present.  */
+
 	  *nbytes = have_read_record;
-	  generate_error (&dtp->common, ERROR_END, NULL);
+	  generate_error (&dtp->common, ERROR_CORRUPT_FILE, NULL);
 	  return;
 	}
 
@@ -507,6 +495,11 @@ read_block_direct (st_parameter_dt *dtp,
 	    }
 	  else
 	    {
+	      /* Let's make sure the file position is correctly set for the
+		 next read statement.  */
+
+	      next_record_r_unf (dtp, 0);
+	      us_read (dtp, 0);
 	      generate_error (&dtp->common, ERROR_SHORT_RECORD, NULL);
 	      return;
 	    }
@@ -637,7 +630,8 @@ write_buf (st_parameter_dt *dtp, void *b
 	  return FAILURE;
 	}
 
-      dtp->u.p.current_unit->strm_pos += (gfc_offset) nbytes; 
+      dtp->u.p.current_unit->strm_pos += (gfc_offset) nbytes;
+      dtp->u.p.current_unit->bytes_left -= (gfc_offset) nbytes;
 
       return SUCCESS;
 
Index: gcc/testsuite/gfortran.dg/read_eof_4.f90
===================================================================
--- gcc/testsuite/gfortran.dg/read_eof_4.f90	(revision 119411)
+++ gcc/testsuite/gfortran.dg/read_eof_4.f90	(working copy)
@@ -1,16 +1,30 @@
 ! { dg-do run }
-! PR 27575 : This test checks the error checking for end of file condition.
+! PR 27575 and PR 30009: This test checks the error checking for end
+! of file condition.
 ! Derived from test case in PR.
-! Submitted by Jerry DeLisle <jvdelisle@verizon.net>.
+! Submitted by Jerry DeLisle <jvdelisle@verizon.net>, modified by
+! Thomas Koenig <Thomas.Koenig@online.de>
+
       program test
       integer i1,i2,i3
       open(unit=11,form='unformatted')
-      write(11)i1, i2     
+      write (11) 1, 2
+      write (11) 3, 4
       close(11,status='keep')
+
       open(unit=11,form='unformatted')
-      read(11, eND=100) i1, i2, i3
+
+      read(11, ERR=100) i1, i2, i3
       call abort()
- 100  read(11, end=110) i3
-      call abort() 
- 110  close(11,status='delete')
+  100 continue
+      if (i1 /= 1 .or. i2 /= 2) call abort
+
+      read(11, ERR=110) i1, i2, i3
+      call abort()
+  110 continue
+      if (i1 /= 3 .or. i2 /= 4) call abort
+
+      read(11, end=120) i3
+      call abort()
+ 120  close(11,status='delete')
       end
-------------- next part --------------
! { dg-do run }
! PR 30059 - exceeding the record length was misrepresented as an EOF
!            on read and ignored on write 
      program main
      integer i,j
      open (10, form="unformatted", access="direct", recl=4)
      write (10, rec=1, err=10) 1,2
      call abort()
 10   continue
      read (10,  rec=1, err=20) i, j
      call abort()
 20   continue
      end
-------------- next part --------------
! { dg-do run }
! Test the error message when an unformatted file has become
! corrupted.
program main
  implicit none
  integer :: i1, i2
  integer :: ios
  character(len=50) :: msg

  ! Write out a truncated unformatted sequential file by
  ! using unformatted stream.

  open (10, form="unformatted", access="stream", file="foo.dat", &
  status="unknown")
  write (10) 16, 1
  close (10, status="keep")

  ! Try to read
  open (10, file="foo.dat", form="unformatted", access="sequential")
  i1 = 0
  i2 = 0
  read (10, iostat=ios, iomsg=msg) i1, i2
  if (ios == 0) call abort
  if (i1 /= 1) call abort
  print *,msg
  close (10, status="delete")
end program main


More information about the Gcc-patches mailing list