Bug 29053 - Consecutive STREAM I/O file positions mixed up
Consecutive STREAM I/O file positions mixed up
Status: RESOLVED FIXED
Product: gcc
Classification: Unclassified
Component: fortran
4.2.0
: P3 normal
: ---
Assigned To: Not yet assigned to anyone
:
: 28747 (view as bug list)
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2006-09-13 02:32 UTC by Jerry DeLisle
Modified: 2006-09-15 13:35 UTC (History)
1 user (show)

See Also:
Host: i686-pc-linux-gnu
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2006-09-14 01:21:46


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jerry DeLisle 2006-09-13 02:32:54 UTC
With the following test case and no optimization, the dtp pointer is duplicated resulting in the dtp-rec values getting mixed up during consecutive writes:

program avl
   implicit none
   real dt, t, a(10)
   integer i, place
   dt = 1.e-6
   a = real( (/ (i, i=1, 10) /) )
   open(unit=11, file='a.dat', access='stream')
   open(unit=12, file='b.dat', access='stream')
   do i = 1, 10
      t = i * dt
      write(11) t
      write(12) a
   end do
   close(11)
   close(12)
end program avl

Test case from Steve Kargl.  The end result should be a.dat file of length 40 and b.dat file of length 400.  The result is:

-rw-rw-r-- 1 jerry jerry  396 Sep 12 19:32 a.dat
-rw-rw-r-- 1 jerry jerry  436 Sep 12 19:32 b.dat

With -O1 this program works fine.

With gdb you can see the transfer calls given the same dtp pointer for both files.
Comment 1 kargl 2006-09-13 02:45:11 UTC
It fails at all optimization levels on FreeBSD.
Comment 2 Andrew Pinski 2006-09-13 03:05:22 UTC
(In reply to comment #1)
> It fails at all optimization levels on FreeBSD.
If a.dat and b.dat are still there, nothing changes in file size.  Make sure you removed them before running the program.
Comment 3 Jerry DeLisle 2006-09-14 01:21:46 UTC
Assembly output which does not work because it is using the same block of memory for the st_parameter_dt structure for both WRITEs, the file position pointer is in this structure, but not set before the calls because it is suppose to be wherever it was left at.

	movl	$.LC1, -368(%ebp)
	movl	$13, -364(%ebp)
	movl	$11, -372(%ebp)
	movl	$0, -376(%ebp)
	leal	-376(%ebp), %eax
	movl	%eax, (%esp)
	call	_gfortran_st_write
snip

	movl	$.LC1, -368(%ebp)
	movl	$16, -364(%ebp)
	movl	$12, -372(%ebp)
	movl	$0, -376(%ebp)
	leal	-376(%ebp), %eax
	movl	%eax, (%esp)
	call	_gfortran_st_write

Assembly output with -O1 shows that in this case, two separate blocks of memory are being used for the two separate st_parameter_dt structures.  In this case the two writes are kept independent as they should be.

	movl	$.LC0, -324(%ebp)
	movl	$13, -320(%ebp)
	movl	$11, -328(%ebp)
	movl	$0, -332(%ebp)
	movl	%esi, -624(%ebp)
	movl	%esi, (%esp)
	call	_gfortran_st_write

snip

	movl	$.LC0, -600(%ebp)
	movl	$16, -596(%ebp)
	movl	$12, -604(%ebp)
	movl	$0, -608(%ebp)
	leal	-608(%ebp), %ebx
	movl	%ebx, (%esp)
	call	_gfortran_st_write

The STREAM I/O assumes that the dtp structure is global, static, and unique to each unit.  Evidently this is not the case.  To fix this, we can allocate the POS pointer for STREAM within the gfc_unit structure which is allocated at run time when OPENed and will remain static and unique.

I will proceed with a patch to do this.
Comment 4 patchapp@dberlin.org 2006-09-15 03:00:40 UTC
Subject: Bug number PR29053

A patch for this bug has been added to the patch tracker.
The mailing list url for the patch is http://gcc.gnu.org/ml/gcc-patches/2006-09/msg00571.html
Comment 5 Jerry DeLisle 2006-09-15 13:16:25 UTC
Subject: Bug 29053

Author: jvdelisle
Date: Fri Sep 15 13:16:15 2006
New Revision: 116970

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=116970
Log:
2006-09-14  Jerry DeLisle  <jvdelisle@gcc.gnu.org>

	PR libgfortran/29053
	* io.h (gfc_unit): Add variable, strm_pos, to track
	STREAM I/O file position.
	* file_pos.c (st_rewind): Set strm_pos to beginning.
	* open.c (new_unit): Initialize strm_pos.
	* read.c (read_x): Bump strm_pos.
	* inquire.c (inquire_via_unit): Return strm_pos value.
	* transfer.c (read_block),(read_block_direct),(write_block)
	(write_buf): Seek to strm_pos - 1.  Update strm_pos when done.
	(pre_position): Initialize strm_pos.
	(data_transfer_init): Set strm_pos if DT_HAS_REC.
	(finalize_transfer): Flush file, no need to update strm_pos.

Modified:
    trunk/libgfortran/ChangeLog
    trunk/libgfortran/io/file_pos.c
    trunk/libgfortran/io/inquire.c
    trunk/libgfortran/io/io.h
    trunk/libgfortran/io/open.c
    trunk/libgfortran/io/read.c
    trunk/libgfortran/io/transfer.c

Comment 6 Jerry DeLisle 2006-09-15 13:32:25 UTC
Subject: Bug 29053

Author: jvdelisle
Date: Fri Sep 15 13:32:12 2006
New Revision: 116971

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=116971
Log:
2006-09-15  Jerry DeLisle  <jvdelisle@gcc.gnu.org>

	PR libgfortran/29053
	* gfortran.dg/streamio_9.f90: New test.
	* gfortran.dg/streamio_10.f90: New test.

Added:
    trunk/gcc/testsuite/gfortran.dg/streamio_10.f90
    trunk/gcc/testsuite/gfortran.dg/streamio_9.f90
Modified:
    trunk/gcc/testsuite/ChangeLog

Comment 7 Jerry DeLisle 2006-09-15 13:33:47 UTC
Fixed on 4.2, will not go to 4.1.
Comment 8 Jerry DeLisle 2006-09-15 13:35:25 UTC
*** Bug 28747 has been marked as a duplicate of this bug. ***