Systematic Errors in Fortran Programs
Are there Systematic Errors in Fortran Programs?
We consider systematic errors to be features in the code which:
And yes there are. We usually see of the order of one anomaly per 50 lines of commented code.
Error Detection by fpt
fpt traps many classes of error and anomaly. Some issues are always trapped, some are trapped by specific fpt commands, and some are detected by instrumenting the code so that they are exposed at run-time. The commands used are shown for each of the classes of error described below.
There are some classes of systematic error which fpt cannot yet trap. These are also listed, and we hope to trap them in the future. If you are aware of any classes of error not listed here please tell us!
The Classes of Error
Note that some of the issues listed here do not always cause errors. These are listed because they may cause errors or may cause problems in migration. Please follow the links from the headings for more detailed descriptions.
Issues in Variable Names and Declarations
Keywords used for symbols
Fortran keywords are not reserved words. Words like PROGRAM, TYPE and DATA can be used for variables. This causes surprisingly few problems. However, we have seen some errors, and it does wonders for the readability of the code.
Intrinsic Function Names used for Symbols
Fortran intrinsic function names are also not reserved and may be used for variables. There are hundreds of them, and it is quite easy to use one of the more obscure ones by accident. The most dangerous cases are where they are used to name arrays.
Inconsistent Use of Names
Two issues are of particular importance:
Equivalence of Different Types or Kinds
Equivalence of different real kinds usually arises by accident and will cause an error. Equivalence of different integer kinds used for bit and byte manipulation may not be portable.
Objects Forced to Unaligned Addresses
Sequence derived type constructs, COMMON statements and (non-standard) structure definitions may force variables to poorly aligned addresses. This can expose compiler errors and will usually lead to inefficiency.
Errors in Single Statements
Array References Out-of-Bounds
Compilers usually trap array references out-of-bounds where the array indices are static expressions. Array bounds can usually be checked at run-time, but run-time bounds checking may be turned off to improve run speed, and some systems only check that a reference is within the array and do not verify the bounds of the separate indices.
Unsafe Data Type Coercions
The most common problem of this type is the use of integer variables as if they were logical. Fortran does not define a translation between integer and logical, and different systems use different conventions.
Loss of Precision
The use of a single low-precision object may degrade the results from all of the high precision components in an expression.
Accidental Whole Array Assignments
If an unsubscripted array is assigned a scalar value, all elements of the array receive that value. If the indices of an array reference are omitted in error, the entire array is overwritten.
Zero Integer Expressions
In Fortran, the results of integer divisions or exponentiation of integers are integer. Sub-expressios like (2/3) and 10**(-9) have the value 0. This leads to some interesting errors.
Structural Errors in Multiple Sub-programs and Statements
Unreachable code does not necessarily indicate an error. Sections of code may be switched in or out of compilation by macro pre-processor switches or by the use of Fortran parameters. However, it does sometimes indicate a problem.
Inconsistent Order of Evaluation
If an expression contains two or more function invocations the Fortran standard explicitly states that the order of evaluation is undefined. This causes problems:
Errors in Usage of Variables
The issues here are:
Unused Statement Labels
Unused labels have no effect on program execution, but they may reduce the code readability and may indicate a problem.
Inconsistent Sub-program Arguments
In general, the actual arguments passed to a sub-program should match the formal arguments in the sub-program definition in:
Compilers usually make these checks if the sub-program interface is visible in the compilation unit where the call is made, and in the case of INTENT, if the INTENT is declared in the interface. Usually, no check is made if the sub-program interface is not visible, and most of the errors observed occur in this case.
A large number of errors are observed in the INTENT of sub-program arguments, and this issue is therefore treated separately in this list.
INTENT of Arguments
The INTENT of a sub-program argument may be declared to be IN, OUT, INOUT or may be undeclared. The Fortran standard expliitly states that the declared INTENT may be used to guide code generation. Therefore an error may occur if:
An error may occur if a sub-program accesses an optional argument which was not present in the current call. To protect against this, access to optional arguments may be enclosed in IF PRESENT(...) constructs.
Inconsistent Use of Logical Units
Errors may occur if the same logical unit number is used to access two or more files. If an OPEN statement opens a file on a unit which is already in use, the file attached to that unit is immediately closed. Some systems do not flush the file buffers.
Failure to Export Overloads
Sub-programs may be setup to overload operations on derived types. For example, the * operator may be overloaded. If the overloads are specified in a Fortran module and are not exported, compilation errors will occur when the overload is used, and the problem will be detected and fixed.
However, it is possible to overload the assignment operator. In this case, if the overload is not exported, no error occurs and the assignment simply copies the right-hand-side quantity to the left-hand-side. The overload fails silently.
Compilers are computer programs, and where modern Fortran is combined with all of the legacy of extended FORTRAN 77, they are asked to do a great deal. There will be bugs, and systems need to be in place to identify them.
These are not systematic errors because programmers remove them rapidly as they occur. They are included in this list simply to comment that they are also reported by the analysis tools.
Errors in Legacy Code
COMMON blocks are layed out separately in every sub-program in which they are referenced. When there are multiple text definitions of a COMMON block there is a serious risk of mis-alignment. When this occurs, objects at the same COMMON block address are accidentally made equivalent.
This is a legacy issue because COMMON blocks are disappearing from use. However, many legacy codes are important and errors from this source must be trapped.
Multiple DATA Initialisation of COMMON Blocks
In FORTRAN 77 there was no problem in initialising the same COMMON block in multiple BLOCK DATA sub-programs. In extended FORTRAN 77, for example, DEC VAX systems, COMMON blocks could also be initialised in multple subroutines and functions. But under Linux, OSX and Unix this will not work. Every initialisation of a COMMON block initialises the whole block, and any uninitialised components are set to zero. The COMMON block is finally populated by which ever initialisation regime happened to be linked last. All other data are lost.
Fixed Format Anomalies
The introduction of the free-format layout in Fortran 90 eliminated a host of potential errors. The most important cases are:
Issues which fpt Can Not Yet Trap
Units and Dimensions
It is possible, by static analysis, to analyse the code and to infer the relationships between the units and dimansions of the variables. Research is in progress, and the current version of fpt (Version 4.0-e) has an experimental command to check units.
It is also possible to modify the code to replace all REAL and COMPLEX declarations and types by emulated types and to attach units and dimansions to each instance. These are then propagated and tested at run-time. Again, research is in progress. fpt has commands which will re-engineer the code and the run-time support is under development.
Fortran pointers, particularly those which are components of derived types, can be accidentally de-referenced when they are passed as sub-program arguments. A handler is needed to check for this situation.
Suppose we have two 2-D arrays, A and B. In a DO loop, A(i,j) is associated in some way with B(i,j). Subsequently we find an loop in which A(i,j) is associated with B(j,i). We should raise a diagnostic asking whether the assciation is the wrong way around.
Copyright ©1995 to 2017 Software Validation Ltd. All rights reserved.