Re: [PATCH] Automatics in equivalence statements

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Automatics in equivalence statements

Andreas Schwab-2
On Aug 14 2019, Mark Eggleston <[hidden email]> wrote:

>     * gfortran.dg/auto_in_equiv_3.f90: New test.

This test fails everywhere.

Andreas.

--
Andreas Schwab, [hidden email]
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Automatics in equivalence statements

Jakub Jelinek
On Sat, Sep 28, 2019 at 10:33:26PM +0200, Andreas Schwab wrote:
> On Aug 14 2019, Mark Eggleston <[hidden email]> wrote:
>
> >     * gfortran.dg/auto_in_equiv_3.f90: New test.
>
> This test fails everywhere.

Yes, and _2 on i686-linux at -O0.

To me both testcases are undefined behavior.
E.g. the first one has:
  subroutine suba(option)
    integer, intent(in) :: option
    integer, automatic :: a
    integer :: b
    integer :: c
    equivalence (a, b)
    if (option.eq.0) then
      ! initialise a and c
      a = 9
      c = 99
      if (a.ne.b) stop 1
      if (loc(a).ne.loc(b)) stop 2
    else
      ! a should've been overwritten
      if (a.eq.9) stop 3
    end if
  end subroutine suba
My understanding is that because a is explicitly automatic and b is automatic too
(implicitly), the whole equivalence is automatic, so if you call this
subroutine with non-zero option, you read an uninitialized variable and
compare it to 9.  That can result in anything, .false., .true., disk
formatting, you can't rely on some other routine laying out its automatic
variable at exactly the same spot and overwriting the memory in there, not
to mention that the compiler can easily spot the uninitialized use too.
Similarly in the second test, returning address of an automatic variable
from a function is already something e.g. the C/C++ FEs warn about, because
you really can't do anything useful with that address, it can't be
dereferenced, or even the comparisons to addresses of other automatic
variables that left their scope is wrong.

IMHO if you want to check if a variable is SAVEd or AUTOMATIC, you want to
recurse, either directly or indirectly, pass the address of the variable in
the outer subroutine down to the inner one and compare there, SAVEd
variables need to have the same address, while AUTOMATIC variables where
both the outer and inner variable is at that point still in the scope need
to have the addresses different.

Though, in order to have in Fortran a recursively callable subroutine, one
needs to use RECURSIVE.
So, IMHO we want 4 testcases out of these 2, two dg-do compile only which
will verify the tests compile when mixing automatic with no explicit
save/automatic in equivalence and will -fdump-tree-gimple and scan the
gimple dump to verify there is equiv.\[0-9]* variable which is not static,
and then two runtime testcases like (one with just -fdec-static, one with
also -fno-automatic, though guess it doesn't matter that much, as recursive
already implies that it is automatic).
program test
  integer :: dummy
  integer, parameter :: address = kind(loc(dummy))
  integer(address) :: addr
  addr = 0
  call sub (0, addr)
contains
  recursive subroutine sub (option, addr)
    integer, intent(in) :: option
    integer(address), intent(in) :: addr
    integer, automatic :: a
    integer :: b
    integer(address) :: c
    equivalence (a, b)
    if (option.eq.0) then
      a = 9
      if (a.ne.b) stop 1
      if (loc(a).ne.loc(b)) stop 2
      c = loc(a)
      call sub (1, c)
      if (a.ne.9) stop 3
    else
      a = 10
      if (a.ne.b) stop 4
      if (loc(a).ne.loc(b)) stop 5
      if (addr.eq.loc(a)) stop 6
    end if
  end subroutine sub
end program test

        Jakub
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Automatics in equivalence statements

Mark Eggleston
Thanks, as you point out all the test needs to do is verify that that a
variable with an AUTOMATIC attribute can be used in an EQUIVALENCE and
and that the items in the EQUIVALENCE are on the stack by using in a
recursive routine.

I've created a patch to replace the existing test cases and have sent it
to this e-mail thread https://gcc.gnu.org/ml/fortran/2019-09/msg00123.html

regards,

Mark

On 30/09/2019 11:24, Jakub Jelinek wrote:

> On Sat, Sep 28, 2019 at 10:33:26PM +0200, Andreas Schwab wrote:
>> On Aug 14 2019, Mark Eggleston <[hidden email]> wrote:
>>
>>>      * gfortran.dg/auto_in_equiv_3.f90: New test.
>> This test fails everywhere.
> Yes, and _2 on i686-linux at -O0.
>
> To me both testcases are undefined behavior.
> E.g. the first one has:
>    subroutine suba(option)
>      integer, intent(in) :: option
>      integer, automatic :: a
>      integer :: b
>      integer :: c
>      equivalence (a, b)
>      if (option.eq.0) then
>        ! initialise a and c
>        a = 9
>        c = 99
>        if (a.ne.b) stop 1
>        if (loc(a).ne.loc(b)) stop 2
>      else
>        ! a should've been overwritten
>        if (a.eq.9) stop 3
>      end if
>    end subroutine suba
> My understanding is that because a is explicitly automatic and b is automatic too
> (implicitly), the whole equivalence is automatic, so if you call this
> subroutine with non-zero option, you read an uninitialized variable and
> compare it to 9.  That can result in anything, .false., .true., disk
> formatting, you can't rely on some other routine laying out its automatic
> variable at exactly the same spot and overwriting the memory in there, not
> to mention that the compiler can easily spot the uninitialized use too.
> Similarly in the second test, returning address of an automatic variable
> from a function is already something e.g. the C/C++ FEs warn about, because
> you really can't do anything useful with that address, it can't be
> dereferenced, or even the comparisons to addresses of other automatic
> variables that left their scope is wrong.
>
> IMHO if you want to check if a variable is SAVEd or AUTOMATIC, you want to
> recurse, either directly or indirectly, pass the address of the variable in
> the outer subroutine down to the inner one and compare there, SAVEd
> variables need to have the same address, while AUTOMATIC variables where
> both the outer and inner variable is at that point still in the scope need
> to have the addresses different.
>
> Though, in order to have in Fortran a recursively callable subroutine, one
> needs to use RECURSIVE.
> So, IMHO we want 4 testcases out of these 2, two dg-do compile only which
> will verify the tests compile when mixing automatic with no explicit
> save/automatic in equivalence and will -fdump-tree-gimple and scan the
> gimple dump to verify there is equiv.\[0-9]* variable which is not static,
> and then two runtime testcases like (one with just -fdec-static, one with
> also -fno-automatic, though guess it doesn't matter that much, as recursive
> already implies that it is automatic).
> program test
>    integer :: dummy
>    integer, parameter :: address = kind(loc(dummy))
>    integer(address) :: addr
>    addr = 0
>    call sub (0, addr)
> contains
>    recursive subroutine sub (option, addr)
>      integer, intent(in) :: option
>      integer(address), intent(in) :: addr
>      integer, automatic :: a
>      integer :: b
>      integer(address) :: c
>      equivalence (a, b)
>      if (option.eq.0) then
>        a = 9
>        if (a.ne.b) stop 1
>        if (loc(a).ne.loc(b)) stop 2
>        c = loc(a)
>        call sub (1, c)
>        if (a.ne.9) stop 3
>      else
>        a = 10
>        if (a.ne.b) stop 4
>        if (loc(a).ne.loc(b)) stop 5
>        if (addr.eq.loc(a)) stop 6
>      end if
>    end subroutine sub
> end program test
>
> Jakub
>
--
https://www.codethink.co.uk/privacy.html