Skip to content

Commit

Permalink
fix: format string overflow in diag_integral (#1624)
Browse files Browse the repository at this point in the history
  • Loading branch information
rem1776 authored Dec 18, 2024
1 parent 01a3a00 commit 33373c9
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 21 deletions.
44 changes: 27 additions & 17 deletions diag_integral/diag_integral.F90
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ module diag_integral_mod
fms_init, &
mpp_pe, mpp_root_pe,&
FATAL, write_version_number, &
stdlog
stdlog, string
use fms2_io_mod, only: file_exists
use constants_mod, only: radius, constants_init
use mpp_mod, only: mpp_sum, mpp_init
Expand Down Expand Up @@ -195,7 +195,6 @@ module diag_integral_mod
!-------------------------------------------------------------------------------
character(len=160) :: format_text !< format statement for header
character(len=160) :: format_data !< format statement for data output
logical :: do_format_data = .true. !< a data format needs to be generated ?
integer :: nd !< number of characters in data format statement
integer :: nt !< number of characters in text format statement

Expand Down Expand Up @@ -711,6 +710,8 @@ subroutine write_field_averages (Time)
integer :: nn, ninc, nst, nend, fields_to_print
integer :: i, kount
integer(i8_kind) :: icount
character(len=128) :: xtime_str
logical :: use_exp_format

!-------------------------------------------------------------------------------
! each header and data format may be different and must be generated
Expand Down Expand Up @@ -764,6 +765,12 @@ subroutine write_field_averages (Time)
!-------------------------------------------------------------------------------
xtime = get_axis_time (Time-Time_init_save, time_units)

!-------------------------------------------------------------------------------
! check if the time value is too long for decimal output
!-------------------------------------------------------------------------------
xtime_str = trim(string(xtime))
use_exp_format = len_trim(xtime_str(1:INDEX(xtime_str, "."))) .ge. 9

!-------------------------------------------------------------------------------
! generate the new header and data formats.
!-------------------------------------------------------------------------------
Expand All @@ -774,7 +781,7 @@ subroutine write_field_averages (Time)
nst = 1 + (nn-1)*fields_per_print_line
nend = MIN (nn*fields_per_print_line, num_field)
if (print_header) call format_text_init (nst, nend)
call format_data_init (nst, nend)
call format_data_init (nst, nend, use_exp_format)
if (diag_unit /= 0) then
write (diag_unit,format_data(1:nd)) &
xtime, (field_avg(i),i=nst,nend)
Expand Down Expand Up @@ -890,18 +897,22 @@ end subroutine format_text_init
!! <b> Parameters: </b>
!!
!! @code{.f90}
!! integer, intent(in), optional :: nst_in, nend_in
!! integer, intent(in) :: nst_in, nend_in
!! @endcode
!!
!! @param [in] <nst_in, nend_in> starting/ending integral index which will be
!! included in this format statement
!! @param [in] <use_exp_format> if true, uses exponent notation for the first format code
!! to avoid overflow with larger time values
!!
subroutine format_data_init (nst_in, nend_in)
subroutine format_data_init (nst_in, nend_in, use_exp_format)

integer, intent(in), optional :: nst_in !< starting/ending integral index which will be
integer, intent(in) :: nst_in !< starting/ending integral index which will be
!! included in this format statement
integer, intent(in), optional :: nend_in !< starting/ending integral index which will be
integer, intent(in) :: nend_in !< starting/ending integral index which will be
!! included in this format statement
logical, intent(in) :: use_exp_format !< if true, uses exponent notation for the first format code
!! to avoid overflow with larger time values

!-------------------------------------------------------------------------------
! local variables:
Expand All @@ -917,28 +928,27 @@ subroutine format_data_init (nst_in, nend_in)
! integrals. this section is 9 characters long.
!-------------------------------------------------------------------------------
nd = 9
format_data(1:nd) = '(1x,f10.2'
if( use_exp_format ) then
format_data(1:nd) = '(1x,e10.2'
else
format_data(1:nd) = '(1x,f10.2'
endif

!-------------------------------------------------------------------------------
! define the indices of the integrals that are to be written by this
! format statement.
!-------------------------------------------------------------------------------
if ( present (nst_in) ) then
nst = nst_in
nend = nend_in
else
nst = 1
nend = num_field
endif
nst = nst_in
nend = nend_in

!-------------------------------------------------------------------------------
! complete the data format. use the format defined for the
! particular integral in setting up the format statement.
!-------------------------------------------------------------------------------
do i=nst,nend
nc = len_trim(field_format(i))
format_data(nd+1:nd+nc+5) = ',1x,' // field_format(i)(1:nc)
nd = nd+nc+5
format_data(nd+1:nd+nc+4) = ',1x,' // field_format(i)(1:nc)
nd = nd+nc+4
end do

!-------------------------------------------------------------------------------
Expand Down
1 change: 0 additions & 1 deletion test_fms/diag_integral/test_diag_integral.F90
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ program test_diag_integral
type(time_type) :: Time_init, Time

!testing and generating answers
integer :: i, j, k !> counters for do loop
real(r8_kind) :: area_sum !> global area. sum of the grid cell areas.
real(r8_kind) :: itime !> made up time
!> The field_avg* values are only declared as r8_kind because they correspond to the values
Expand Down
3 changes: 0 additions & 3 deletions test_fms/diag_integral/test_diag_integral2.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,8 @@ EOF
mkdir -p INPUT

test_expect_success "test_diag_integral r4" 'mpirun -n 1 ./test_diag_integral_r4'
rm diag_integral.out
test_expect_success "test_diag_integral r8" 'mpirun -n 1 ./test_diag_integral_r8'
rm diag_integral.out

rm input.nml
rm -rf INPUT

test_done

0 comments on commit 33373c9

Please sign in to comment.