This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug libfortran/31880] New: silent data corruption in gfortran read statement
- From: "roconnor at health dot usf dot edu" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: 9 May 2007 15:56:36 -0000
- Subject: [Bug libfortran/31880] New: silent data corruption in gfortran read statement
- Reply-to: gcc-bugzilla at gcc dot gnu dot org
This program should print out "1".
Instead, it prints out "1024":
program r3
integer*4 a(1025),b(1025),c(1025),d(2048),e(1022)
do i=1,2048
d(i)=i
end do
open (3,file='a',form='unformatted')
write (3) a,b,c,d,e
rewind 3
read (3) a,b,c,d
close (3)
print *,d(1)
end
output of /opt/bin/gfortran -v:
Using built-in specs.
Target: x86_64-unknown-linux-gnu
Configured with: ../gcc-4.1.2/configure --prefix=/opt --disable-multilib
Thread model: posix
gcc version 4.1.2
It was compiled with:
/opt/bin/gfortran -Wall -o r3 r3.f
and run with:
LD_LIBRARY_PATH=/opt/lib64 ./r3
This patch fixes it:
--- gcc-4.1-4.1.2/gcc-4.1.2/libgfortran/io/unix.c 2006-05-29
22:51:26.000000000 -0400
+++ gcc-4.1-4.1.2_patched/gcc-4.1.2/libgfortran/io/unix.c 2007-05-08
19:22:09.000000000 -0400
@@ -465,7 +465,7 @@
if (n < 0)
return NULL;
- s->physical_offset = where + n;
+ s->physical_offset = m + n;
s->active += n;
}
else
@@ -476,7 +476,7 @@
if (do_read (s, s->buffer + s->active, &n) != 0)
return NULL;
- s->physical_offset = where + n;
+ s->physical_offset = m + n;
s->active += n;
}
The problem is that s->physical_offset is being miscalculated as
where+n, which is the requested read start address plus the bytes read
from the disk to fill the buffer. It should be where+s->active+n
(=m+n), the requested read start address plus the as-yet-unread bytes
still in the buffer plus the bytes read from the disk to fill the
buffer. The s->logical_offset is correctly set to where+*len.
What happens is that if an unbuffered (<8192 bytes) read of more than
half the buffer (array b in the example) exceeds the data remaining in
the buffer, the remaining data will get moved to the beginning of the
buffer, and some amount of data will be read from disk to fill the
buffer. If the next read (array c) is of the same length, it will
also exceed the data remaining in the buffer, the remaining data will
get moved to the beginning of the buffer, and this time the length of
the data read from the disk (n) will be the same as the requested read
length (*len). Since the physical_offset is being set to where+n and
s->logical_offset is set to where+*len, they are equal. If the next
read is >=8192 bytes (array d), it will be unbuffered, which would
normally cause the data remaining in the buffer to be ignored and
cause a seek to re-read that data along with the rest of the request,
from the disk. But the code will decide that it doesn't have to seek
because physical_offset=logical_offset. So the remaining data in the
buffer will be lost.
--
Summary: silent data corruption in gfortran read statement
Product: gcc
Version: 4.1.2
Status: UNCONFIRMED
Severity: critical
Priority: P3
Component: libfortran
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: roconnor at health dot usf dot edu
GCC build triplet: x86_64-unknown-linux-gnu
GCC host triplet: x86_64-unknown-linux-gnu
GCC target triplet: x86_64-unknown-linux-gnu
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31880