Constant and pass-by-reference

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

Constant and pass-by-reference

Hafiz Abid Qadeer
Hi,
I am a Fortran newbie. I was investigating a crash in an openacc
benchmark. But digging a bit deeper, it looks that problem has nothing
to do with openacc but a general issue with a 'parameter' being passed
by reference. The following program demonstrate the problem. The example
looks contrived but actual code used the "var" in an openacc kernel and
it gets written due to an implicit copy clause. I am using an explicit
write (var = 4) here instead.

module test1
      contains
      subroutine  crash(var)
        implicit none
        integer var
        var = 4
      end subroutine
end module test1


program main
  use test1
  implicit none
  integer           g_var
  parameter         (g_var = 5)
  call crash(g_var)
end program main


As I understand it, a constant value is passed to a subroutine which
tries to modify it. As value was passed by reference, the callee tries
to write to read-only memory and segfaults.

Can you kindly confirm if this is the correct understanding of the
semantics of the Fortran. Also I am wondering should compiler issue a
warning in such cases as I did not see a warning even with -Wall.

Thanks,
--
Hafiz Abid Qadeer
Mentor Embedded/CodeSourcery
Reply | Threaded
Open this post in threaded view
|

Re: Constant and pass-by-reference

Arjen Markus-4
Hello Hafiz,

I do not know if the compiler can be expected to catch all such cases
- after all, the module may be compiled and stored in some library and
then used in a separate build step. In that case the information that
the actual argument is not a variable would be lost. You can, however,
help the compiler by stating the intent for the dummy argument (var):

integer, intent(out) :: var

Now, the compiler will complain when it tries to compile the main program.

Should the actual routine be a C function, then you can use an
interface block to state the exact semantics (at least in this
respect) of the function. No need for a Fortran routine.

Hope this helps.

Regards,

Arjen


Op di 18 jun. 2019 om 15:13 schreef Hafiz Abid Qadeer <[hidden email]>:

>
> Hi,
> I am a Fortran newbie. I was investigating a crash in an openacc
> benchmark. But digging a bit deeper, it looks that problem has nothing
> to do with openacc but a general issue with a 'parameter' being passed
> by reference. The following program demonstrate the problem. The example
> looks contrived but actual code used the "var" in an openacc kernel and
> it gets written due to an implicit copy clause. I am using an explicit
> write (var = 4) here instead.
>
> module test1
>       contains
>       subroutine  crash(var)
>         implicit none
>         integer var
>         var = 4
>       end subroutine
> end module test1
>
>
> program main
>   use test1
>   implicit none
>   integer           g_var
>   parameter         (g_var = 5)
>   call crash(g_var)
> end program main
>
>
> As I understand it, a constant value is passed to a subroutine which
> tries to modify it. As value was passed by reference, the callee tries
> to write to read-only memory and segfaults.
>
> Can you kindly confirm if this is the correct understanding of the
> semantics of the Fortran. Also I am wondering should compiler issue a
> warning in such cases as I did not see a warning even with -Wall.
>
> Thanks,
> --
> Hafiz Abid Qadeer
> Mentor Embedded/CodeSourcery
Reply | Threaded
Open this post in threaded view
|

Re: Constant and pass-by-reference

Tobias Burnus
In reply to this post by Hafiz Abid Qadeer
Hi Hafiz,

to add to what Arjen wrote.

Am 18.06.19 um 15:13 schrieb Hafiz Abid Qadeer:
> a general issue with a 'parameter' being passed by reference. The following program demonstrate the problem. The example looks contrived but actual code used the "var" in an openacc kernel and it gets written due to an implicit copy clause. […]
>
> As I understand it, a constant value is passed to a subroutine which
> tries to modify it. As value was passed by reference, the callee tries
> to write to read-only memory and segfaults.

Fortran by default passes values by reference.* If you use the VALUE
attribute, i.e.,

      subroutine  crash(var)
        implicit none
        integer var
        value var
or
        integer, value :: var
the variable is passed by value.*

(*The Fortran standard actually does not state how it is passed, it just
states the semantic. Depending on the argument type, passing as VALUE
might not work or semantic might require, e.g., contiguous memory. Then
the caller generates a temporary value with (depending on the "intent")
copy-in and/or copy-out and passes this one as a pointer.)


> Also I am wondering should compiler issue a
> warning in such cases as I did not see a warning even with -Wall.

Warning is not that simple without specifying an "intent(in)",
"intent(out)" or "intent(inout)". With intent, the compiler can check
this at compile time, otherwise it would need to keep track whether the
variable is always modified, assume:

if (var !=5) then

  var = 4

end if

In this case, the program would work and be perfectly valid as the
parameter g_var is not modified.

Tobias

PS: I head that in the old days, such a program didn't crash but did
modify the value of the constant. That would even work for:
"call crash(5)" - after which "5" had the value 4. But that ways decades
before my first encounter with Fortran.

Reply | Threaded
Open this post in threaded view
|

Re: Constant and pass-by-reference

Arjen Markus-4
Op di 18 jun. 2019 om 23:32 schreef Tobias Burnus <[hidden email]>:
>
>
> PS: I head that in the old days, such a program didn't crash but did
> modify the value of the constant. That would even work for:
> "call crash(5)" - after which "5" had the value 4. But that ways decades
> before my first encounter with Fortran.
>

Things have changed a lot since these very old days - I do remember
having to work around that particular problem on an IBM machine. To
illustrate how much things have changed: nowadays the IEEE rules for
floating-point numbers are (almost) universal, but their development
has taken a lot of time and effort. We now take that for granted, as
we do many other things, but these things did not appear
automatically.

Regards,

Arjen
Reply | Threaded
Open this post in threaded view
|

Re: Constant and pass-by-reference

Mark Eggleston
In reply to this post by Arjen Markus-4

On 18/06/2019 14:22, Arjen Markus wrote:

> Hello Hafiz,
>
> I do not know if the compiler can be expected to catch all such cases
> - after all, the module may be compiled and stored in some library and
> then used in a separate build step. In that case the information that
> the actual argument is not a variable would be lost. You can, however,
> help the compiler by stating the intent for the dummy argument (var):
>
> integer, intent(out) :: var
>
> Now, the compiler will complain when it tries to compile the main program.
I have also come across this problem. In my opinion it is better to
catch such a fault at compile time rather than run time.

A scheme that checks a dummy variable's intent is OUT or INOUT when a
value is assigned and issues a warning would help.

Such a warning could be controlled by -Wall with perhaps an new option
-Wintent. When used with -Werror the program will then fail to compile.

This would encourage the use of intent with dummy.

regards

Mark

>
> Should the actual routine be a C function, then you can use an
> interface block to state the exact semantics (at least in this
> respect) of the function. No need for a Fortran routine.
>
> Hope this helps.
>
> Regards,
>
> Arjen
>
>
> Op di 18 jun. 2019 om 15:13 schreef Hafiz Abid Qadeer <[hidden email]>:
>> Hi,
>> I am a Fortran newbie. I was investigating a crash in an openacc
>> benchmark. But digging a bit deeper, it looks that problem has nothing
>> to do with openacc but a general issue with a 'parameter' being passed
>> by reference. The following program demonstrate the problem. The example
>> looks contrived but actual code used the "var" in an openacc kernel and
>> it gets written due to an implicit copy clause. I am using an explicit
>> write (var = 4) here instead.
>>
>> module test1
>>        contains
>>        subroutine  crash(var)
>>          implicit none
>>          integer var
>>          var = 4
>>        end subroutine
>> end module test1
>>
>>
>> program main
>>    use test1
>>    implicit none
>>    integer           g_var
>>    parameter         (g_var = 5)
>>    call crash(g_var)
>> end program main
>>
>>
>> As I understand it, a constant value is passed to a subroutine which
>> tries to modify it. As value was passed by reference, the callee tries
>> to write to read-only memory and segfaults.
>>
>> Can you kindly confirm if this is the correct understanding of the
>> semantics of the Fortran. Also I am wondering should compiler issue a
>> warning in such cases as I did not see a warning even with -Wall.
>>
>> Thanks,
>> --
>> Hafiz Abid Qadeer
>> Mentor Embedded/CodeSourcery

--
https://www.codethink.co.uk/privacy.html

Reply | Threaded
Open this post in threaded view
|

Re: Constant and pass-by-reference

Steve Kargl
On Fri, Jun 21, 2019 at 09:29:53AM +0100, Mark Eggleston wrote:

>
> On 18/06/2019 14:22, Arjen Markus wrote:
> > Hello Hafiz,
> >
> > I do not know if the compiler can be expected to catch all such cases
> > - after all, the module may be compiled and stored in some library and
> > then used in a separate build step. In that case the information that
> > the actual argument is not a variable would be lost. You can, however,
> > help the compiler by stating the intent for the dummy argument (var):
> >
> > integer, intent(out) :: var
> >
> > Now, the compiler will complain when it tries to compile the main program.
> I have also come across this problem. In my opinion it is better to
> catch such a fault at compile time rather than run time.
>
> A scheme that checks a dummy variable's intent is OUT or INOUT when a
> value is assigned and issues a warning would help.
>
> Such a warning could be controlled by -Wall with perhaps an new option
> -Wintent. When used with -Werror the program will then fail to compile.
>
> This would encourage the use of intent with dummy.
>

I suspect that this will have a high false positive rate.
My Makefiles already contain

# gfortran is too noisy
FFLAGS += -Wno-maybe-uninitialized -Wno-conversion -Wno-integer-division

to suppress issues with these options.

I would not support adding it to -Wall.  

--
Steve
Reply | Threaded
Open this post in threaded view
|

Re: Constant and pass-by-reference

Mark Eggleston

On 21/06/2019 14:58, Steve Kargl wrote:

> On Fri, Jun 21, 2019 at 09:29:53AM +0100, Mark Eggleston wrote:
>> On 18/06/2019 14:22, Arjen Markus wrote:
>>> Hello Hafiz,
>>>
>>> I do not know if the compiler can be expected to catch all such cases
>>> - after all, the module may be compiled and stored in some library and
>>> then used in a separate build step. In that case the information that
>>> the actual argument is not a variable would be lost. You can, however,
>>> help the compiler by stating the intent for the dummy argument (var):
>>>
>>> integer, intent(out) :: var
>>>
>>> Now, the compiler will complain when it tries to compile the main program.
>> I have also come across this problem. In my opinion it is better to
>> catch such a fault at compile time rather than run time.
>>
>> A scheme that checks a dummy variable's intent is OUT or INOUT when a
>> value is assigned and issues a warning would help.
>>
>> Such a warning could be controlled by -Wall with perhaps an new option
>> -Wintent. When used with -Werror the program will then fail to compile.
>>
>> This would encourage the use of intent with dummy.
>>
> I suspect that this will have a high false positive rate.
I have a preliminary patch that implements this scheme (attached).
Initially it was unaware of the VALUE attribute and was later changed.
Running the gfortran test using "make -j 8 check-fortran" resulted in 8
failures from 3 test cases (earlier version):

c_by_val_5.f90
coarray_24.f90
warn_concat.f90

Once the patch was aware of VALUE, the failures for c_by_val_5.f90 no
longer occurred. Adding intent to the dummy variables in coarray_24.f90
and warn_concart.f90 Rrduced to the failures to zero.

I not sure what you mean by "false positive" unless it is for FORTRAN
code earlier than Fortran 90 which does not have intent. Dummy variables
can simply have INTENT attributes added resulting in clearer code.

The patch currently includes this warning message:

"Dummy variable %qs in assignment has no INTENT specified, use
INTENT(INOUT) or INTENT(OUT) at %L"

I'm not happy with it as it was written before taking into account the
VALUE attribute. Any suggestions will be appreciated.

I do think that this patch will be valuable as it can help catch bugs at
compile time instead of run time. If there is a consensus that the use
of -Wall is a bad idea I can disassociate it from -Wintent.

> My Makefiles already contain
>
> # gfortran is too noisy
> FFLAGS += -Wno-maybe-uninitialized -Wno-conversion -Wno-integer-division
>
> to suppress issues with these options.
>
> I would not support adding it to -Wall.
>
--
https://www.codethink.co.uk/privacy.html


0001-Constant-and-pass-by-reference.patch (2K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Constant and pass-by-reference

Dominique d'Humières-2
In reply to this post by Hafiz Abid Qadeer
How is this related to

Bug 64958 - Warn if INTENT(IN) is changed by passing to no-intent argument
and
Bug 88079 - warn about procedure arguments without INTENT
?

Note that I certainly don’t want the warning in -Wall: it will break a lot of valid f77 codes.

Dominique