https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85975

            Bug ID: 85975
           Summary: Incorrect size for spread array
           Product: gcc
           Version: 8.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libfortran
          Assignee: unassigned at gcc dot gnu.org
          Reporter: stephan.kramer at imperial dot ac.uk
  Target Milestone: ---

With the following program

program foo
  implicit none

  call bar(2, 3, 5, 7)

  contains

  subroutine bar(k, l, m, n)
    integer, intent(in) :: k, l, m, n
    real, dimension(k) :: a
    real, dimension(k,l):: b
    real, dimension(k,l,m):: c
    real, dimension(k,l,m,n):: d

    print *, size(spread(A, 1, 1))
    print *, size(spread(b, 1, 1))
    print *, size(spread(c, 1, 1))
    print *, size(spread(d, 1, 1))

  end subroutine

end program

I get the following result:

$ gfortran test2.f90 
skramer@gyre:~/tst/gfortran8$ ./a.out 
           2
           6
           0
         210
skramer@gyre:~/tst/gfortran8$ ./a.out 
           0
           6
   754395868
         210

i.e. the results for the A and c arrrays are incorrect (and vary between
subsequent reruns).

After some digging in the libfortran source I think this is due to a bug in the 
GFC_DTYPE_COPY_SETRANK macro introduced in
https://gcc.gnu.org/ml/gcc-patches/2018-01/msg00369.html, where line 421 of
libgfortran/libgfortran.h changed from

(a)->dtype = (((b)->dtype & ~GFC_DTYPE_RANK_MASK) | n ); \

to

(a)->dtype.rank = ((b)->dtype.rank | n ); \

The thing is that the "| n" makes sense in the previous case where the relevant
bits that store the previous rank have been zeroed out first. Now that rank is
a separate field, I think it should just be:

(a)->dtype.rank = n

Note that in the example above the even ranked arrays (B and D) do get the
correct result. This is because in those cases it happens to be that
new_rank==(old_rank | new_rank) (3 == 2 | 3 and 5 == 4 | 5). In the case of
arrays A and C however, we get 1 | 2 == 3 and 3 | 4 == 7, so that the rank of
the resulting spread array is too big, and the size calculations uses spurious
uninitialised array extents.

I have found, what I think are, related issues, when passing the result of
spread of a rank-3 array into a subroutine, where in the "internal pack"
routine  would sometimes try to allocate a temporary that is way too big and
cause an out of memory error (similar to
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85816). Unfortunately this one
seems a little harder to reproduce in a small program.

Reply via email to