[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