[patch] Fix libgfortran/29627
Thomas Koenig
Thomas.Koenig@online.de
Mon Oct 30 11:01:00 GMT 2006
:ADDPATCH fortran:
Hello world,
this is a fix for PR 29627, including a little cleanup.
Regression-tested against 4.3.0 on i686-pc-linux-gnu.
OK for trunk? What about 4.2 and 4.1?
Thomas
2006-10-29 Thomas Koenig <Thomas.Koenig@online.de>
PR libfortran/29627
* libgfortran.h: Add ERROR_SHORT_RECORD
* runtime/error.c (translate_error): Add case
for ERROR_SHORT_RECORD.
* io/transfer.c (read_block_direct): Separate codepaths
for stream and record unformatted I/O. Remove unneeded
tests for standard input, padding and formatted I/O.
If the record is short, read in as much data as possible,
then raise the error.
-------------- next part --------------
Index: runtime/error.c
===================================================================
--- runtime/error.c (revision 117910)
+++ runtime/error.c (working copy)
@@ -435,6 +435,10 @@ translate_error (int code)
p = "Write exceeds length of DIRECT access record";
break;
+ case ERROR_SHORT_RECORD:
+ p = "Short record on unformatted read";
+ break;
+
default:
p = "Unknown error code";
break;
Index: libgfortran.h
===================================================================
--- libgfortran.h (revision 117910)
+++ libgfortran.h (working copy)
@@ -413,6 +413,7 @@ typedef enum
ERROR_INTERNAL_UNIT,
ERROR_ALLOCATION,
ERROR_DIRECT_EOR,
+ ERROR_SHORT_RECORD,
ERROR_LAST /* Not a real error, the last error # + 1. */
}
error_codes;
Index: io/transfer.c
===================================================================
--- io/transfer.c (revision 117910)
+++ io/transfer.c (working copy)
@@ -359,82 +359,73 @@ read_block (st_parameter_dt *dtp, int *l
static void
read_block_direct (st_parameter_dt *dtp, void *buf, size_t *nbytes)
{
- int *length;
- void *data;
size_t nread;
+ int short_record;
- if (!is_stream_io (dtp))
+ if (is_stream_io (dtp))
{
- if (dtp->u.p.current_unit->bytes_left < (gfc_offset) *nbytes)
+ if (sseek (dtp->u.p.current_unit->s,
+ dtp->u.p.current_unit->strm_pos - 1) == FAILURE)
{
- /* For preconnected units with default record length, set
- bytes left to unit record length and proceed, otherwise
- error. */
- if (dtp->u.p.current_unit->unit_number == options.stdin_unit
- && dtp->u.p.current_unit->recl == DEFAULT_RECL)
- dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
- else
- {
- if (dtp->u.p.current_unit->flags.pad == PAD_NO)
- {
- /* Not enough data left. */
- generate_error (&dtp->common, ERROR_EOR, NULL);
- return;
- }
- }
-
- 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;
- }
-
- *nbytes = (size_t) dtp->u.p.current_unit->bytes_left;
+ generate_error (&dtp->common, ERROR_END, NULL);
+ return;
}
- if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED &&
- dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
+ nread = *nbytes;
+ if (sread (dtp->u.p.current_unit->s, buf, &nread) != 0)
{
- length = (int *) nbytes;
- data = read_sf (dtp, length, 0); /* Special case. */
- memcpy (buf, data, (size_t) *length);
+ generate_error (&dtp->common, ERROR_OS, NULL);
return;
}
- dtp->u.p.current_unit->bytes_left -= (gfc_offset) *nbytes;
+ dtp->u.p.current_unit->strm_pos += (gfc_offset) nread;
+
+ if (nread != *nbytes) /* Short read, e.g. if we hit EOF. */
+ generate_error (&dtp->common, ERROR_END, NULL);
+
+ return;
}
- else
+
+ /* Unformatted file with records */
+ if (dtp->u.p.current_unit->bytes_left < (gfc_offset) *nbytes)
{
- if (sseek (dtp->u.p.current_unit->s,
- dtp->u.p.current_unit->strm_pos - 1) == FAILURE)
+ short_record = 1;
+ nread = (size_t) dtp->u.p.current_unit->bytes_left;
+ *nbytes = nread;
+
+ 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;
}
}
- nread = *nbytes;
+ else
+ {
+ short_record = 0;
+ nread = *nbytes;
+ }
+
+ dtp->u.p.current_unit->bytes_left -= nread;
+
if (sread (dtp->u.p.current_unit->s, buf, &nread) != 0)
{
generate_error (&dtp->common, ERROR_OS, NULL);
return;
}
- if (!is_stream_io (dtp))
+ if (nread != *nbytes) /* Short read, e.g. if we hit EOF. */
{
- if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
- dtp->u.p.size_used += (gfc_offset) nread;
+ *nbytes = nread;
+ generate_error (&dtp->common, ERROR_END, NULL);
+ return;
}
- else
- dtp->u.p.current_unit->strm_pos += (gfc_offset) nread;
- if (nread != *nbytes) /* Short read, e.g. if we hit EOF. */
+ if (short_record)
{
- if (!is_stream_io (dtp))
- generate_error (&dtp->common, ERROR_EOR, NULL);
- else
- generate_error (&dtp->common, ERROR_END, NULL);
+ generate_error (&dtp->common, ERROR_SHORT_RECORD, NULL);
+ return;
}
}
@@ -595,7 +586,8 @@ unformatted_read (st_parameter_dt *dtp,
/* By now, all complex variables have been split into their
constituent reals. For types with padding, we only need to
read kind bytes. We don't care about the contents
- of the padding. */
+ of the padding. If we hit a short record, then sz is
+ adjusted accordingly, making later reads no-ops. */
sz = kind;
for (i=0; i<nelems; i++)
-------------- next part --------------
! { dg-do run }
! PR 29627 - partial reads of unformatted records
program main
character a(3)
character(len=50) msg
open(10, form="unformatted", status="unknown")
write (10) 'a'
write (10) 'c'
a = 'b'
rewind 10
read (10, err=20, iomsg=msg) a
call abort
20 continue
if (msg .ne. "Short record on unformatted read") call abort
if (a(1) .ne. 'a' .or. a(2) .ne. 'b' .or. a(3) .ne. 'b') call abort
close (10, status="delete")
end program main
More information about the Fortran
mailing list