ISO/IEC JTC 1/SC 22/OWGV N 0145 Draft of language-specific annex for Fortran Date 28 August 2008 Contributed by Dan Nagle Original file name Fortran_Draft.txt Notes To: OWG-V Subject: Draft Fortran Annex From: Dan Nagle Date: 2008 August 28 Draft of the Fortran Annex of the OWG-V TR This Annex provides Fortran-specific advice for the items in clause 6, specifically the 6.x.5 Avoiding the vulnerability or mitigating its effects subclause. This annex does not repeat the other sections of each vulnerability. Therefore, readers will find OWG-V n0138 helpful when reading this document. This draft is written with the draft Fortran 2008 standard in mind, it is available from http://www.j3-fortran.org as 08-007r2. This draft includes subclauses for the vulnerabilities suggested by J3 at 185. If the form of the annexes includes other subclauses, this draft annex will need them added as well. DRAFT %%% 6.1 BRS Leveraging Experience Avoid the use of decremental features. Avoid the use of processor extensions, including processor-defined intrinsic procedures. %%% 6.2 BQF Unspecified Behavior The Fortran term is undefined behavior (see also 6.4). Review subclause 1.3 and Annex A for a list of undefined behavior. %%% 6.3 EWF Undefined Behavior Use only those forms and relationships where the Fortran standard provides an interpretation. %%% 6.4 FAB Implementation-defined Behavior The Fortran term is processor-dependent behavior (see also 6.4). Use only forms and relationships where the result of the program execution does not depend upon the processor choice from among the possibilities defined by the processor dependency. Review Annex A for a list of processor dependencies. %%% 6.5 MEM Deprecated Language Features See Annex B of f08. Review Annex A for a list of deleted or obsolescent features. %%% 6.6 BVQ Unspecified Functionality No specific Fortran recommendation. %%% 6.7 NMP Pre-processor Directives No Fortran preprocessor. %%% 6.8 NAI Choice of Clear Names Avoid names differing only in case. Use unqualified private statements to limit export of names from modules. Use only clauses on use statements to limit import of names from modules. %%% 6.9 AJN Choice of Filenames and other External Identifiers Take care with external identifiers as they are all processor-dependent. Note that the on an include line may not represent a file name, or the file name might be qualified by a processor-dependent search path. %%% 6.9+ YZS Unused Subprogram Argument Use compiler options to detect unused dummy arguments. Use explicit interfaces to ensure correct references. Make unused arguments optional and test for presence to trap references with the unused argument. Use argument intents to prevent inadvertent stores to the caller's storage. %%% 6.10 XYR Unused Variable Use implicit none to require explicit declaration of all variable names. Use translator options to generate warning when unused variables are encountered. Use a compiler option to warn of undeclared variables if use of implicit none is impractical. Use unqualified private statements to limit export of names from modules. Use only clauses on use statements to limit import of names from modules. %%% 6.11 YOW Identifier Name Reuse Do not use blocks to override names from other nested scopes. When using a block to declare a new name, specifically ensure that the name is unique across all enclosing scopes and enclosed scopes. Note that Fortran doesn't have a scope resolution operator. Use consistent names within groups of related entities. Ensure that all names are 63 characters or fewer. %%% 6.11+ JIO Type Choice Use explicit kind type parameters to select the correct kind. Use the selected_?_kind() intrinsics to select the kind type values. Centralize an application's kind selections in a single module. %%% 6.12 IHN Type System Always use IMPLICIT NONE. Avoid implicit type conversions and mixed-mode arithmetic. Use compiler options to enable warnings where appropriate. %%% 6.13 STR Bit Representations Always use the Fortran bit model ordering. Do not manipulate bits of negative numbers without documenting the treatment of negative numbers on the target platform. %%% 6.14 PLF Floating-point Arithmetic Do not test for real equality. Do not use comparisons where the difference between > and >= or < and <= are crucial. Compare real quantities within a tolerance rather than for strict equality. Do not use real loop counters. Use the inquiry intrinsics to determine the characteristics of the real model rather than computing them. Use the intrinsics to get or set the fields of real data. Avoid the use of bit constants as floating point constants. Do not assume knowledge of the rounding mode of the translator. Explicitly control the rounding mode of input/output transfers. Do not assume that register precision equals memory precision. %%% 6.15 CCB Enumerator Issues Use enumerators only when interfacing to C programs. Do not assume variables of enumeration type are the same as any kind of integer. %%% 6.16 FLC Numeric Conversion Errors Check the value of input data. Check values before critical operations. Set an error to occur when appropriate. Use explicit conversion intrinsics to indicate intention. Always use an explicit kind as part of a real or complex constant. Use a named constant with explicit kind for real or complex constants. Be aware of the unexpected properties when using list directed input, or namelist input. %%% 6.17 CJM String Termination Use character operations rather than explicit loops. When explicit loops are necessary, use inquiry intrinsics to determine the loop count. %%% 6.18 XYX Boundary Beginning Violation Check values used as array indices. Use whole array operations when possible to avoid array index calculations. Adjust extent lower bounds as indicated by the problem. Use bounds checking to find out-of-bounds conditions. %%% 6.19 XYZ Unchecked Array Indexing Check values used as array indices. Use whole-array operations when possible to avoid array index calculations. Use inquiry intrinsics to determine array bounds. %%% 6.20 XYW Buffer Overflow in Stack Check values used as array indices. Use whole-array operations when possible to avoid array index calculations. Use inquiry intrinsics to determine array bounds. Use explicit ALLOCATE statements to place large object on the heap. Indicate in code where implicit allocate/deallocate is expected. Do not use superfluous "(:)" to indicate whole array operations. %%% 6.21 XZB Buffer Overflow in Heap Indicate in code where implicit allocate or deallocate is expected. Check values used as array indices. Use whole-array operations when possible to avoid array index calculations. Use inquiry intrinsics to determine array bounds. Use explicit ALLOCATE statements to place large object on the heap. Indicate in code where implicit allocate/deallocate is expected. Do not use superfluous "(:)" to indicate whole array operations. %%% 6.22 HFC Pointer Casting and Pointer Type Changes Does not happen in Fortran. %%% 6.23 RVG Pointer Arithmetic Does not happen in Fortran. %%% 6.24 XYH Null Pointer Dereference Verify that pointers and allocatables are defined and are not null by use of the associated intrinsic or the allocated intrinsic. %%% 6.25 XYK Dangling Reference to Heap Use finalizers to clear pointers and allocatables in derived types. Use automatic allocation/deallocation. Put allocate and deallocate in the same module to make analysis tractable. %%% 6.26 SYM Templates and Generics Not applicable to Fortran. %%% 6.27 LAV Initialization of Variables Ensure all variables are initialized before use. Provide a default initialization for derived type variables. Keep variable usage confined to one module to make analysis tractable. Ensure that defined assignment assigns to all components. Use constructors rather than component-wise assignments. Avoid use of COMMON. Do not rely upon variables being initialized to zero. %%% 6.28 XYY Wrap-around Error Check values for proper range between bit operations and arithmetic operations. Never use bit operations where an intrinsic procedure performs the intended calculation (for example, using and-with-sign-bit in place of sign()). %%% 6.29 XZI Sign Extension Error Use explicit conversion between differently sized integers. Do not use transfer(). Do not use equivalence. %%% 6.30 JCW Operator Precedence/Order of Evaluation Use parenthesis where order of evaluation is critical. Use auxiliary variables to order operations. Beware of high levels of optimization and isolate critical operations in separately-compiled procedures. %%% 6.31 SAM Side-effects and Order of Evaluation Use pure functions whenever possible. Use subroutines when side effects are needed. Declare argument intents to enable checks of argument usage. %%% 6.32 KOA Likely Incorrect Expression Simplify expressions. Use variables to hold partial results of long expressions. Vertically align similar terms in long expressions to ease visual checking. %%% 6.33 XYQ Dead and Deactivated Code Dead code or unreachable code should be removed. If available, use compiler options to warn of unreachable code. %%% 6.34 CLL Switch Statement and Static Analysis Ensure that select case constructs cover all cases. Use a case default clause as needed, perhaps to provide notice of unexpected values. %%% 6.35 EOJ Demarcation of Flow Control Always use block forms of do-loops. Always use end- statements. Use named constructs for all but possibly the smallest constructs. Indent code. Use a syntax-highlighting editor. %%% 6.36 TEX Loop Control Variables Use the loop induction variable inside a loop (as opposed to an auxiliary variable), especially as an array index. Check that procedure references within a loop do not modify the loop variable. Ensure that procedures within a loop have argument intents for all arguments. %%% 6.37 XZH Off-by-one Error Use inquiry intrinsics to set loop limits. Use counted do-loops, do concurrent or forall for array computations. Ensure that loop-local indexes have the same kind as variables of the same name outside the loop. Use whole array operations if possible. Never use sentinel values for loop control, explicitly test for not associated when processing data structures involving pointers. %%% 6.38 EWD Structured Programming Use block structures in preference to go to statements. Name all structures where a cycle or exit statement is used and name the target structure of cycle and exit statements. Do not use alternate returns, return a status variable and test its value instead. Do not use branch specifiers for input/output statements; use the status variable and test its value instead. %%% 6.39 CSJ Passing Parameters and Return Values Use argument intents. Minimize side effects in subroutines. Use pure or elemental functions wherever possible. %%% 6.39+ DTK Sentinel Values Do not rely upon sentinel values, which may be especially prevalent with procedure arguments and return values. Sentinel values spread between different modules may be harder to locate and remove. Use specific predicate procedures instead. %%% 6.40 DCM Dangling References to Stack Frames Never associate a pointer having a greater longevity with a target having a shorter longevity. Use compiler options where available to warn of possible situations where the the pointer outlives the target. %%% 6.41 OTR Subprogram Signature Mismatch Always use explicit interfaces. Use optional arguments when needed. Use optional arguments when eliminating unused arguments from references. Use argument intents. %%% 6.41+ NSQ Library Signature Use compiler options or tools to generate explicit interfaces for libraries lacking them. Use a more recent edition of a library lacking explicit interfaces. %%% 6.41+ PUS Extra Intrinsics Give all application procedures an explicit interface, or the external attribute, to prevent confusion with intrinsics. Use the intrinsic attribute to specify intrinsic procedures. %%% 6.42 GDL Recursion Minimize the use of recursion. Convert recursive calculations to iterative calculations. Guarantee a recursive calculation has a maximum depth. %%% 6.43 NZN Returning Error Status Treat errors locally if possible. Return a status variable, and always check its value. %%% 6.44 RUE Termination Strategy Each application should have an error handling strategy. When an application is parallel, whether to kill the task, or halt the task but preserve its resources, or kill the application, must be decided and used consistently. %%% 6.45 AMV Type-breaking Reinterpretation of Data Do not use equivalence to reinterpret bit patterns. Do not use transfer. Do not use storage sequences unless necessary. When necessary, ensure consistent definition of common blocks. %%% 6.46 XYL Memory Leak Ensure allocate statements match deallocate statements. Ensure that each deallocate statement is reached via all possible paths from the corresponding allocate statements. Use automatic deallocation where possible. Use allocatable variables rather than pointers. Put allocate and deallocate in the same module to make analysis tractable. %%% 6.47 TRJ Use of Libraries Use libraries with explicit interfaces (modules). If necessary, use compiler options to check interfaces where explicit interfaces are not present. %%% 6.48 NYY Dynamically-linked Code and Self-modifying Code Consider the use of static linking when useful.