This is the mail archive of the
fortran@gcc.gnu.org
mailing list for the GNU Fortran project.
[patch, libgfortran] PR32752 Segfault on WRITE with modified unix_stream structure
- From: Jerry DeLisle <jvdelisle at verizon dot net>
- To: Fortran List <fortran at gcc dot gnu dot org>
- Cc: gcc-patches <gcc-patches at gcc dot gnu dot org>
- Date: Sat, 14 Jul 2007 09:24:39 -0700
- Subject: [patch, libgfortran] PR32752 Segfault on WRITE with modified unix_stream structure
:ADDPATCH fortran:
Hi Folks,
This one was ugly and difficult. The final fix appears straightforward, but it
was hard to find this stealthy bug.
The problem was off by one errors that tended to cancel coupled with stream I/O
not setting a variable correctly. This failure was only seen when I moved the
location of the buffer pointer within the unix_stream structure. The failure
showed only with streamio_3.f90.
Fully regression tested on x86-64-Gnu/Linux. I also did some valgrind checks on
streamio_3.f90 and those showed very clean.
No new test case is needed.
OK for trunk?
Regards,
Jerry
2007-07-14 Jerry DeLisle <jvdelisle@gcc.gnu.org>
PR libgfortran/32752
* io/unix.c (unix_stream): Move buffer pointer adjacent to small_buffer.
* io/transfer.c (formatted_transfer_scalar): If stream I/O, set
bytes_used to zero. Fix off by one error in calculation of pos and
skips. Eliminate duplicate pending_spaces check.
Index: unix.c
===================================================================
--- unix.c (revision 126610)
+++ unix.c (working copy)
@@ -97,7 +97,6 @@ typedef struct
gfc_offset dirty_offset; /* Start of modified bytes in buffer */
gfc_offset file_length; /* Length of the file, -1 if not seekable. */
- char *buffer;
int len; /* Physical length of the current buffer */
int active; /* Length of valid bytes in the buffer */
@@ -108,6 +107,7 @@ typedef struct
int unbuffered; /* =1 if the stream is not buffered */
+ char *buffer;
char small_buffer[BUFFER_SIZE];
}
unix_stream;
@@ -587,7 +587,7 @@ fd_alloc_w_at (unix_stream * s, int *len
s->ndirty = where + *len - start;
else
s->ndirty = s->dirty_offset + s->ndirty - start;
- s->dirty_offset = start;
+ s->dirty_offset = start;
}
s->logical_offset = where + *len;
Index: transfer.c
===================================================================
--- transfer.c (revision 126610)
+++ transfer.c (working copy)
@@ -949,7 +949,10 @@ formatted_transfer_scalar (st_parameter_
}
bytes_used = (int)(dtp->u.p.current_unit->recl
- - dtp->u.p.current_unit->bytes_left);
+ - dtp->u.p.current_unit->bytes_left);
+
+ if (is_stream_io(dtp))
+ bytes_used = 0;
switch (t)
{
@@ -1156,9 +1159,9 @@ formatted_transfer_scalar (st_parameter_
case FMT_TR:
consume_data_flag = 0;
- pos = bytes_used + f->u.n + dtp->u.p.skips;
- dtp->u.p.skips = f->u.n + dtp->u.p.skips;
- dtp->u.p.pending_spaces = pos - dtp->u.p.max_pos;
+ dtp->u.p.skips += f->u.n;
+ pos = bytes_used + dtp->u.p.skips - 1;
+ dtp->u.p.pending_spaces = pos - dtp->u.p.max_pos + 1;
/* Writes occur just before the switch on f->format, above, so
that trailing blanks are suppressed, unless we are doing a
@@ -1188,8 +1191,6 @@ formatted_transfer_scalar (st_parameter_
if (bytes_used == 0)
{
dtp->u.p.pending_spaces -= f->u.n;
- dtp->u.p.pending_spaces = dtp->u.p.pending_spaces < 0 ? 0
- : dtp->u.p.pending_spaces;
dtp->u.p.skips -= f->u.n;
dtp->u.p.skips = dtp->u.p.skips < 0 ? 0 : dtp->u.p.skips;
}