WRF - Errors in OPTIONAL Arguments
OPTIONAL Violations in WRF - The Issue
An OPTIONAL violation occurs when an optional argument is accessed in its sub-program code without a check that the argument is present.
In WRF versions 3.6.1 and 3.4.1, there are:
|OPTIONAL arguments accessed without a check for presence||1,360||987|
|OPTIONAL, always present, accessed without a check||1,325||977|
|OPTIONAL, not always present, accessed without a check||35||10|
OPTIONAL Violations and Compiler or Run-Time System Error Detection
If you access an optional argument which isn't present it crashes the program doesn't it?
This is a simple OPTIONAL violation:
PROGRAM opt_1 INTERFACE SUBROUTINE s_char(str) CHARACTER*(*), OPTIONAL :: str END SUBROUTINE s_char END INTERFACE CALL s_char END PROGRAM opt_1 SUBROUTINE s_char(str) CHARACTER*(*), OPTIONAL :: str CHARACTER*64 local_str local_str = "local_part "//str WRITE(6,*)local_str END SUBROUTINE s_char
The argument str is declared OPTIONAL and is not present in the call to s_char. However, it is always accessed in the code of s_char. This does not crash under ifort or gfortran. The output from the program is:
It does crash, on both of these compilers if the INTERFACE block is left out of the main program.
The code shown below:
PROGRAM opt_2 INTERFACE SUBROUTINE s_char(str) CHARACTER*(*),OPTIONAL :: str END SUBROUTINE s_char END INTERFACE CALL s_char("String is present") CALL s_char END PROGRAM opt_2 SUBROUTINE s_char(str) CHARACTER*(*), OPTIONAL :: str CHARACTER*64 local_str local_str = "local_part "//str WRITE(6,*)local_str END SUBROUTINE s_char
runs under both ifort and gfortran to generate the output:
local_part String is present local_part
If the INTERFACE block is ommitted, it crashes under ifort, but runs under gfortran with the result:
local_part String is present local_part String is present
The attributes of the optional argument are retained from the call where it is present to the next where it is absent.
Finding OPTONAL Errors in WRF
If you have not already done so, set up the WRF test environment as described here.
Change to the fpt/ directory and run fpt on WRFV3.6.1_vanilla.fsp or WRFV3.4.1_vanilla.fsp . Specify the argument %i to command fpt to run interactively, e.g.
$ cd fpt
$ fpt WRFV3.4.1_vanilla.fsp %i
The fpt run will pause to show the diagnostics which have been suppressed. Type a carriage return to continue. About 10,000 diagnostics for WRF3.6.1, or 6,200 for WRFV3.4.1, will stream past (They are all captured in the list file). The fpt run will pause with an interactive prompt.
Turn off paging. Otherwise fpt will pause after each reported OPTIONAL violation. Run the OPTIONAL argument check (Please see CHECK OPTIONAL ARGUMENTS).
FPT> paging off
FPT> check optional arguments
All of the unguarded optional arguments are reported. The report ends with the summary, e.g. for WRFV3.4.1:
Check for unguarded access to OPTIONAL arguments ================================================ Optional arguments: 2118 Not always present and with unguarded references (Errors): 10 Always present but with unguarded references (Warnings): 987 Arguments with possible unguarded references (Warnings): 1 Total number of unguarded references: 1767
Note that in WRFV3.4.1 there are only 10 arguments which are optional and which are sometimes not present in calls to the routines concerned. In WRFV3.6.1 there are 35. These are potential errors. The remaining unguarded optional arguments are always present in the calls. These are no more than maintenance traps.
Note also that the check made by fpt is not completely safe and may generate false positives (Though none have been found). The check is made for code protected by IF (PRESENT(...)) constructs. If a local variable is set equal to the logical value returned by PRESENT() and is itself used to guard references, this is not visible to the current version of fpt.
Does WRF Ever Access OPTIONAL Arguments which are Not PRESENT?
The command INSERT CHECK OF OPTIONAL ARGUMENTS modifies the code to insert a check for the presence of each optional argument at references where it appears to be unguarded. The accesses to optional arguments which are not present are counted, and are reported in the file fpt_optional_check.txt at the end of a run.
The script tools/WRFV3_fpt_experient.csh has been set up to run an experiment as follows:
This process is described in more detail in the wrf_experiments page. Note that the script tools/WRFV3_fpt_experiment.csh has two arguments, the WRF version and the experiment name.
Run the experiment check_optional, e.g.:
$ tools/WRFV3_fpt_experiment.csh WRFV3.6.1 check_optional
The WRF Fortran files built for this experiment are copied to the directories WRFV3.6.1_check_optional/WRFV3/... or WRFV3.4.1_check_optional/WRFV3/... . Compare these files with the original UCAR sources, and with WRFV3.6.1_vanilla/WRFV3... or WRFV3.4.1_vanilla/WRFV3... if you have already made the vanilla (Unchanged) run. We strongly recommend Beyond Compare from Scooter Software to make this comparison. Specify the rule that Fortran comments are delimited by "!" and that comments are unimportant differences.
In our runs, with gfortran and ifort, the wrfout output files are identical to those generated by a standard UCAR build, and the
file fpt_optional_check.txt contains the message that no accesses to missing optional arguments are
detected. In a run of em_b_wave, WRF does not access missing optional arguments. However, em_b_wave only exercises
about 18% of the WRF code, so further tests are required to demonstrate that this never occurs.
Copyright ©1995 to 2020 Software Validation Ltd. All rights reserved.