Hi Yusuke, hi all,

On 3/2/20 12:16 PM, Thomas Koenig wrote:
Would you tell me more information about the project?

Before the introduction of modules and "contained" procedures
(both: Fortran 90), there was no way to declare/define a function
at one place and when using the procedure to know (and, hence,
check) the arguments. – In C, header lines which declare the
prototype of a function are common, hence, the issue does not exist
there. (One can still call a function in C without prototype, but as
it is rarely done on purpose, one can warn for this – or
with -Werror even fail to compile.)

In terms of the language, even procedures in the same file are not
known, i.e.

subroutine foo(x)
   integer ::  x
end

subroutine bar()
  call foo(1.1)  ! < invalid should be integer not real
end

From version to version, gfortran does more tests whether
(a) the call matches the actual declaration (in the same file),
(b) when no interface is known, whether it two usages (calls)
in the same file are both permitted – if one uses "integer" and
the other "real" it is surely wrong.
(c) where an interface block matches either another interface
block or the usage or the actual declaration in the same file.

* * *

In terms of run-time checking, there are two kind of uses:

(a) A code where the interface is not known from the definition
of the procedure. That's either calling the procedure without
an implicit interface ("external") or with a self-written
"interface", which may happen not match the actual procedure
interface.
For instance, a code I recently came across called BLAS's "dcopy"
with a 64bit instead of default-kind integer (32bit).

(b) Even with known interface, having an invalid use of the argument.
For instance, the procedure takes an "integer :: x" as argument and
the call does "call foo(55)". That's perfectly valid as long as the
argument is not modified — otherwise, it crashes.

The simple check is whether the INTENT matches, the interface has
IN and the declaration has INOUT/OUT or whether a constant/intent-in
variable has been passed to an INOUT/OUT variable. – but those are
both for case (a). — One could also run-time check the use (i.e.
annotate the places where the variable is modified) but that can
become very complex. A simple version would be to deduce whether the
input is always modified (unconditionally assigned to or passed to
another procedure with intent OUT/INOUT) and then add the check.

As alluded in the wiki, I was thinking of having some global variable
and then in the procedure call do (pseudo C code):

__gfortran_check_args = {.version=1, .nargs=2, .arg[0].type = int_kind_4,
.arg[0] = readonly, arg[1].type = real_4, filename="abc.f90", line=123, … }
__gfortran_check_func = my_func
my_func (&23, &rvar)

and in the callee "my_func":
if (__gfortran_check_func == my_func)
  {
     if (__gfortran_check_args.nargs != 2) error(wrong number of arguments)
     if (__gfortran_check_args.arg[0] != int_kind_4) error(arg1: wrong arg type)
     if (__gfortran_check_args.arg[0] == readonly) error(arg1: cannot )


  }

The check "__gfortran_check_func == my_func" is needed if one mixes
code which is instrumented with code which is not.


Fortran has aliasing rules which allow for much better optimization
than C; for example, it is not allowed to pass the same actual
argument to several dummy arguments and change one of
them.  The programmer has to follow these rules, or undefined
behavior can occur.

That's another case of (b), e.g.
call sub (a, a, b)

subroutine (x, y, z)
  if (y == 9)
    z = 4
  x = 5
end

is invalid as "x" (alias "a") is modified but the value of "y" (alias "a")
is also accessed. It is perfectly valid to modify "x" if "y" is completely
untouched – or to access both "x" and "y" without modifying. That's really
a run-time condition, i.e.
  if (z == 9) then
    y = 5
  else
    x = 7
  endif
is valid as only "x" or "y" are accessed in this case.

As in my INTENT example: If as in the first example, "x" and "y" are both
accessed unconditionally, one can add a run-time check without much effort.
(And possibly even a compile-time check.) – While for, e.g.,
  if (y == 9) then
    y = 7
    return
  endif
  x = 6
the code is valid only if y == 9.

In terms of the tasks:
* one has to think about how to organize the data in the global variable
  (what information to put there etc.)
* what to check in general
* how to do the checking (in the code vs. library calls to libgfortran).
For instance, something like
  if (arg[1].type != real_4) arg_error ("filename", 123, "my_func",
ERROR_TYPEMISMATCH, 1, __gfortran_arg_check, real_4); would probably be useful:
One only has two string constants in the object file, does the checking in place
but passes all information for the error string on to the library.

One could also do also all checking in libgfortran or …

* * *

As Thomas mentioned, it would be useful to get to know the code a bit before
starting. One useful way is usually to pick some bug report and to create a
patch to fix it. (I usually found ICE (internal compiler error) on invalid code
a good starting point as those tend to be easier. I think someone can try to 
find
some bugs which look simple to be fixed, if you are interested.)

A quick overview is (relative to the GCC source code):
* libgfortran/ is the run-time library; e.g. runtime/error.c handles the 
run-time
errors
* gcc/fortran/ is the Fortran compiler itself. with:
– trans*.c converts the internal representation into the "tree"
  representation of GCC itself.
– The other files operate on the gfortran representation (gfc_symbol, gfc_expr, 
…)
– interface.c does most of the interface-related checks.

Fortran standard: See links at https://gcc.gnu.org/wiki/GFortranStandards
Goal is support Fortran 2018 completely; currently, Fortran 2008 is mostly 
supported
and some bits for Fortran 2018.
For the argument checking, it is probably useful to also check some legacy 
features
like Cray pointers, but mostly/first restricting to standard Fortran is 
sufficient.

Copyright assignment: For all "nontrivial" code changes, the the Free Software
Foundation (FSF) would like to have a copyright assignment. See
https://gcc.gnu.org/contribute.html#legal

Cheers,

Tobias

-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander 
Walter

Reply via email to