Version Intel® Fortran Compiler version 18.0 and newer
Product Intel® Parallel Studio XE
Operating System Windows*, Linux*, macOS*
Architecture IA-32, Intel64
Reading from a variable before it has been written to can result in application errors that are not reproducible and can be difficult to debug, especially for global variables and variables passed as procedure arguments. The Intel® Fortran Compiler version 18 and newer can detect accesses to a wide variety of uninitialized floating-point variables. (The feature is also available in earlier Intel compilers with some restrictions.) This is achieved by initializing such floating-point data to a signaling NaN and then trapping the floating-point invalid exception that occurs if the data are used in a floating-point operation before they have been assigned a value by the application.
Method The application should first be compiled and run with the options /fpe:0 /traceback (Windows) or -fpe0 -traceback (Linux or macOS) to ensure there are no unexpected floating-point exceptions from other sources. If there are, these should be corrected.
Next, compile the application with the options /Qinit:snan,arrays /traceback (Windows) or -init=snan,arrays -traceback (Linux or macOS). This automatically sets /fpe:0 (Windows) or -fpe0 (Linux or macOS), which causes floating-point exceptions to be trapped. The “traceback” switch causes any such exceptions to be followed by a lightweight traceback that includes the procedure name, file name and line number where the exception occurred. If the exception results from an operation on an uninitialized floating-point variable, you will typically see the message:
If the “arrays” argument is omitted, uninitialized scalars will be detected, but uninitialized array elements will not.
In general, the following classes of REAL, COMPLEX, INTEGER, or LOGICAL variables of any KIND are supported:
- SAVEd (static) scalar or array variables that are not initialized in the source code
- Local scalars and arrays
- Automatic arrays
- Module variables that are not initialized in the source code
- ALLOCATABLE arrays and scalars
with the following restrictions:
- Variables in EQUIVALENCE groups
- Variables in COMMON
- Derived types, arrays of derived types and their components are not supported
- Dummy procedure arguments are not initialized to a signaling NaN locally. They may be so initialized in the calling procedure, if they meet the above criteria
- References in arguments to intrinsic procedures or I/O statements may not be detected
- Integers can be set to zero, huge or minus_huge
- In a COMPLEX variable, each of the real and imaginary part is separately initialized as REAL.
Warning /Qinit:snan (Windows) or -init=snan (Linux or macOS) unmasks floating-point exceptions so that use of SNaNs in a floating-point operation will be detected and trapped. If you build with optimization, the compiler may speculate floating-point operations, assuming the default floating-point environment in which floating-point exceptions are masked. When you add /Qinit:snan (-init=snan), this speculation may result in exceptions that now get trapped.
The simplest way to avoid this is to reduce the optimization level to /O1 or /Od (-O1 or -O0) when doing uninitialized variable detection. If you wish to maintain optimization, you should add the switch /Qfp-speculation:safe (-fp-speculation=safe) to disable speculation, if there is a possibility that the speculation may cause a floating-point exception.
Another possibility is to add the switch /fp:strict (-fp-model strict), which tells the compiler not to assume the default floating-point environment, but this is likely to have a bigger impact on performance than /Qfp-speculation:safe (-fp-speculation=safe).
Example (Source code at the end of the article)
Whilst it’s usually a good idea to compile with –O0 (Linux or macOS) or /Od (Windows) when debugging, this is not required for uninitialized variable detection. First, make sure the application runs without floating-point exceptions:
No floating-point exceptions, but one or two strange-looking values.
Next, look for uninitialized scalars.
Here we see otherwise uninitialized scalars being initialized to a NaN. The access to the module variable AM at line 39 results in an exception, diagnostic and traceback.
Next, look also for uninitialized arrays.
Array elements that are not explicitly initialized by the application are also being initialized to a NaN. The access to the automatic array F at line 36 results in an exception, diagnostic and traceback. Although the uninitialized variable is not identified by name, the source file and line number make it easy to find. If the application is compiled with -g (Linux or macOS) or /Zi (Windows), it also possible to use a symbolic debugger: when the debugger breaks at the floating-point exception, the variable contents may be examined directly.
Source Code