Bug 34876 - Can't read/write array sections with negative stride not specified
Summary: Can't read/write array sections with negative stride not specified
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 4.3.0
: P3 normal
Target Milestone: ---
Assignee: Jerry DeLisle
URL:
Keywords:
Depends on:
Blocks: 32834
  Show dependency treegraph
 
Reported: 2008-01-19 21:03 UTC by Dick Hendrickson
Modified: 2008-01-26 00:04 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2008-01-23 05:41:31


Attachments
Preliminary patch (611 bytes, patch)
2008-01-24 07:03 UTC, Jerry DeLisle
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Dick Hendrickson 2008-01-19 21:03:56 UTC
The following program prints READ FAILED.  A similar program
with an unformatted, rather than direct access, file also fails.

Dick Hendrickson

      Program qi0011
      CHARACTER(9) BDA(10)
      CHARACTER(9) BDA1(10)
      INTEGER  J_LEN
      ISTAT = -314

      INQUIRE(IOLENGTH = J_LEN) BDA1

      ISTAT = -314
      OPEN (UNIT=48,
     $      STATUS='SCRATCH',
     $      ACCESS='DIRECT',
     $      RECL = j_len,
     $      IOSTAT = ISTAT,
     $      FORM='UNFORMATTED',
     $      ACTION='READWRITE')


      IF (ISTAT /= 0) stop

      BDA = 'xxxxxxxxx'
      WRITE (48,IOSTAT = ISTAT, REC = 10) BDA1(4:3)
      IF ( ISTAT .NE. 0) THEN
        stop ' WRITE FAILED '
      ENDIF

      ISTAT = -314
      READ (48,IOSTAT = ISTAT, REC=10) BDA(4:3)
      IF ( ISTAT .NE. 0) THEN
        stop ' READ FAILED '
      ENDIF
      end
Comment 1 Jerry DeLisle 2008-01-19 21:21:57 UTC
I will check into this one while I am at it as well
Comment 2 Jerry DeLisle 2008-01-20 02:56:55 UTC
Here is a reduced case that illustrates the problem.  Not specifying the negative stride in either the read or write results in a failure. See the commented lines.

      program qi0011
      character(9) bda(10)
      character(9) bda1(10)
      integer  j_len
      istat = -314

      inquire(iolength = j_len) bda1
      
      print '("j_len=",i2)',j_len

      istat = -314
      open (unit=48,
     $      access='direct',
     $      recl = j_len,
     $      status="scratch",
     $      iostat = istat,
     $      form='unformatted',
     $      action='readwrite')

      bda = 'xxxxxxxxx'
      bda1 ='123456789'
      write (48, rec = 10) bda1(4:3:-1)! This works
c      write (48, rec = 10) bda1(4:3)              ! This fails
      read (48, rec=10) bda(7:6:-1)    ! This works
c      read (48, rec=10) bda(7:6)                  ! This fails
      print '(10(a))', bda1
      print '(10(a))', bda
      end

Looking at -fdump-tree-original:

With stride given:
    {
      struct array1_unknown parm.9;

      parm.9.dtype = 625;
      parm.9.dim[0].lbound = 1;
      parm.9.dim[0].ubound = 2;
      parm.9.dim[0].stride = -1;
      parm.9.data = (void *) (character(kind=1)[0:][1:9] *) &bda1[3];
      parm.9.offset = 0;
      _gfortran_transfer_array (&dt_parm.8, &parm.9, 1, 9);
    }

Without stride given:
    {
      struct array1_unknown parm.9;

      parm.9.dtype = 625;
      parm.9.dim[0].lbound = 1;
      parm.9.dim[0].ubound = 0;
      parm.9.dim[0].stride = 1;
      parm.9.data = (void *) (character(kind=1)[0:][1:9] *) &bda1[3];
      parm.9.offset = -4;
      _gfortran_transfer_array (&dt_parm.8, &parm.9, 1, 9);
    }
Comment 3 Jerry DeLisle 2008-01-20 18:10:16 UTC
In the failing case, we have no stride:

Breakpoint 1, gfc_walk_subexpr (ss=0xfc2de0, expr=0x106f6b0)
    at ../../gcc43/gcc/fortran/trans-array.c:5609
(gdb) p *expr->ref

snip
---->      stride = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, dimen_type = 

And in the passing case we do:

Breakpoint 1, gfc_walk_subexpr (ss=0xfc2de0, expr=0x106f6b0)
    at ../../gcc43/gcc/fortran/trans-array.c:5609
snip
---->      stride = {0x106fb70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
(gdb) 

Comment 4 Jerry DeLisle 2008-01-22 02:44:46 UTC
Front End does set default stride to one and does not check fo rthe case of a negative stride.  Unassigning since it is in unfamiliar territory for me.
Comment 5 Jerry DeLisle 2008-01-22 05:27:25 UTC
Changing summary to better reflect what is wrong.
Comment 6 Paul Thomas 2008-01-22 09:03:36 UTC
(In reply to comment #5)
> Changing summary to better reflect what is wrong.
Jerry,

Jerry,

I believe this to be something missing in the library.

Other compilers (G95 and DEC are what I can lay hands on right now), as far as I can see, interpret the io array references as being zero length.

I think that transfer_array is, mostly, doing the right thing.  If I add
      WRITE (48,IOSTAT = ISTAT, REC = 12) BDA1(3:4)
or to any other record >10, the testcase works correctly.  Thus, rather than just returning, with a zero length array, transfer_array has to write a zero length record if the current record is > the number of record in the file.

I am completely lost in the library these days, whereas you are king:) Can you have another look?

Paul
Comment 7 Jerry DeLisle 2008-01-22 14:54:03 UTC
Yes, I will have another look.
Comment 8 Jerry DeLisle 2008-01-23 05:41:31 UTC
I am beginning to see it now. This does not help:

      if (extent[n] <= 0)
	return;

we just bail out right now when we need to actually do something.
Comment 9 Paul Thomas 2008-01-23 06:45:05 UTC
(In reply to comment #8)

> we just bail out right now when we need to actually do something.

Yes, that's what I thought.  In the circumstance where this block "exists", ie. there is one beyond it, bailing out is OK. What does setting the block beyond the current one do, given that it is also bailing out?  I suppose that all the preceeding blocks are written, or the file length is set to have at least that number of blocks?

Anyway, good luck.  I need to try to fix PR34429 asap.

Cheers

Paul

Comment 10 Jerry DeLisle 2008-01-24 05:15:42 UTC
Answering your question.  Putting the write in front of the failing one causes seeking to that record, writing it out and flushing the buffers.  Writing "grows" the file.  This creates "undefined" records from the beginning of the file up to the record written.  With that the file actually has content and a length. (Hard to read record 10 on a file with length zero)
Comment 11 Jerry DeLisle 2008-01-24 07:03:20 UTC
Created attachment 15014 [details]
Preliminary patch

This patch illustrates the fix.  What remains is to check cases of all other I/O (formatted, sequential, stream, etc) with this situation of "zero length" arrays
Comment 12 Jerry DeLisle 2008-01-25 23:35:43 UTC
Subject: Bug 34876

Author: jvdelisle
Date: Fri Jan 25 23:34:53 2008
New Revision: 131848

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=131848
Log:
2008-01-25  Jerry DeLisle  <jvdelisle@gcc.gnu.org>

	PR libfortran/34876
	* io/transfer.c (write_buf): Handle case of zero sized array.
	(transfer_array): Set data pointer to NULL and size to zero.  Then
	make a data transfer and return.

Modified:
    trunk/libgfortran/ChangeLog
    trunk/libgfortran/io/transfer.c

Comment 13 Jerry DeLisle 2008-01-25 23:41:08 UTC
Subject: Bug 34876

Author: jvdelisle
Date: Fri Jan 25 23:40:23 2008
New Revision: 131850

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=131850
Log:
2008-01-25  Jerry DeLisle  <jvdelisle@gcc.gnu.org>

	PR libfortran/34876
	* gfortran.dg/direct_io_9.f: New test.

Added:
    trunk/gcc/testsuite/gfortran.dg/direct_io_9.f
Modified:
    trunk/gcc/testsuite/ChangeLog

Comment 14 Jerry DeLisle 2008-01-26 00:04:21 UTC
Fixed on trunk. Thanks for bug report and test case.