Skip to content

Commit e269673

Browse files
committed
Ensure the buffer provided to MPAS_io_get_var_generic is large enough.
A fixed size array is provided as an input buffer when reading 0d-char character variables. Call MPAS_io_inq_var prior to the read to get the size of the variable’s value, and only proceed with the read if the variable’s value will fit in the provided array. Return an error code if the variable’s value is larger than the provided input buffer.
1 parent 9fa8cb2 commit e269673

File tree

2 files changed

+53
-12
lines changed

2 files changed

+53
-12
lines changed

src/framework/mpas_io.F

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
!
88
module mpas_io
99

10+
#define IO_DEBUG_WRITE(M, ARGS) !call mpas_log_write(M, ARGS)
11+
#define IO_ERROR_WRITE(M, ARGS) call mpas_log_write( M, ARGS, messageType=MPAS_LOG_ERR)
12+
1013
use mpas_derived_types
1114
use mpas_attlist
1215
use mpas_dmpar
@@ -1847,6 +1850,13 @@ subroutine MPAS_io_get_var_generic(handle, fieldname, intVal, intArray1d, intArr
18471850
character (len=:), pointer :: charVal_p
18481851
character (len=:), dimension(:), pointer :: charArray1d_p
18491852

1853+
! local variables returned from MPAS_io_inq_var
1854+
integer :: fieldtype
1855+
integer :: ndims
1856+
integer, dimension(:), pointer :: dimsizes
1857+
character (len=StrKIND), dimension(:), pointer :: dimnames
1858+
character (len=StrKIND) :: message
1859+
18501860
#ifdef MPAS_SMIOL_SUPPORT
18511861
type (SMIOLf_decomp), pointer :: null_decomp
18521862

@@ -1984,22 +1994,41 @@ subroutine MPAS_io_get_var_generic(handle, fieldname, intVal, intArray1d, intArr
19841994
! call mpas_log_write(' value is char')
19851995

19861996
charVal_p => charVal
1997+
1998+
! get the dimension of the char variable to ensure the provided output buffer is large enough
1999+
call MPAS_io_inq_var(handle, fieldname, fieldtype, ndims, dimnames, dimsizes, local_ierr)
2000+
do i = 1, ndims
2001+
message = ' MPAS_io_get_var_generic len(charVal):$i var "'//trim(fieldname)// &
2002+
'" type is $i dim is $i '// trim(dimnames(i))//' size is $i'
2003+
IO_DEBUG_WRITE(message, intArgs=(/len(charVal), fieldtype, i, dimsizes(i)/))
2004+
end do
2005+
! because charVal is provided, assume dimension 1 is the string length
2006+
if (dimsizes(1) > len(charVal)) then
2007+
local_ierr = MPAS_IO_ERR_INSUFFICIENT_BUF
2008+
message = 'Length of string variable "'//trim(fieldname)//'" in file "'//trim(handle % filename)//'"'
2009+
IO_ERROR_WRITE(message, intArgs=[0])
2010+
message = ' exceeds buffer size: len('//trim(fieldname)//')=$i, len(buffer)=$i'
2011+
IO_ERROR_WRITE(message, intArgs=(/dimsizes(1), len(charVal)/))
2012+
else
19872013
#ifdef MPAS_SMIOL_SUPPORT
1988-
local_ierr = SMIOLf_get_var(handle % smiol_file, trim(fieldname), null_decomp, charVal_p)
2014+
local_ierr = SMIOLf_get_var(handle % smiol_file, trim(fieldname), null_decomp, charVal_p)
19892015
#endif
19902016

19912017
#ifdef MPAS_PIO_SUPPORT
1992-
if (field_cursor % fieldhandle % has_unlimited_dim) then
1993-
count2(1) = field_cursor % fieldhandle % dims(1) % dimsize
1994-
pio_ierr = PIO_get_var(handle % pio_file, field_cursor % fieldhandle % fieldid, start2, count2, tempchar)
1995-
charVal(1:count2(1)) = tempchar(1)(1:count2(1))
1996-
else
1997-
start1(1) = 1
1998-
count1(1) = field_cursor % fieldhandle % dims(1) % dimsize
1999-
pio_ierr = PIO_get_var(handle % pio_file, field_cursor % fieldhandle % fieldid, start1, count1, tempchar)
2000-
charVal(1:count1(1)) = tempchar(1)(1:count1(1))
2001-
end if
2018+
if (field_cursor % fieldhandle % has_unlimited_dim) then
2019+
count2(1) = field_cursor % fieldhandle % dims(1) % dimsize
2020+
pio_ierr = PIO_get_var(handle % pio_file, field_cursor % fieldhandle % fieldid, start2, count2, tempchar)
2021+
charVal(1:count2(1)) = tempchar(1)(1:count2(1))
2022+
else
2023+
start1(1) = 1
2024+
count1(1) = field_cursor % fieldhandle % dims(1) % dimsize
2025+
pio_ierr = PIO_get_var(handle % pio_file, field_cursor % fieldhandle % fieldid, start1, count1, tempchar)
2026+
charVal(1:count1(1)) = tempchar(1)(1:count1(1))
2027+
end if
20022028
#endif
2029+
end if
2030+
deallocate(dimsizes)
2031+
deallocate(dimnames)
20032032
else if (present(charArray1d)) then
20042033
! call mpas_log_write(' value is char1')
20052034
#ifdef MPAS_PIO_SUPPORT
@@ -2765,6 +2794,13 @@ subroutine MPAS_io_get_var_generic(handle, fieldname, intVal, intArray1d, intArr
27652794
end if
27662795

27672796
! call mpas_log_write('Checking for error')
2797+
if (local_ierr == MPAS_IO_ERR_INSUFFICIENT_BUF) then
2798+
call MPAS_io_err_mesg(handle % ioContext, local_ierr, .false.)
2799+
io_global_err = local_ierr
2800+
if (present(ierr)) ierr = local_ierr
2801+
return
2802+
endif
2803+
27682804
#ifdef MPAS_PIO_SUPPORT
27692805
if (pio_ierr /= PIO_noerr) then
27702806
io_global_err = pio_ierr
@@ -6498,6 +6534,10 @@ subroutine MPAS_io_err_mesg(ioContext, ierr, fatal)
64986534
call mpas_log_write('MPAS IO Error: Would clobber existing file', MPAS_LOG_ERR)
64996535
case (MPAS_IO_ERR_NOEXIST_READ)
65006536
call mpas_log_write('MPAS IO Error: Attempting to read a file which does not exist.', MPAS_LOG_ERR)
6537+
case (MPAS_IO_ERR_MISSING_DIM)
6538+
call mpas_log_write('MPAS IO Error: Attempting to read a dimension which does not exist.', MPAS_LOG_ERR)
6539+
case (MPAS_IO_ERR_INSUFFICIENT_BUF)
6540+
call mpas_log_write('MPAS IO Error: Attempting to read a variable into a buffer of insufficient size.', MPAS_LOG_ERR)
65016541
case default
65026542
call mpas_log_write('MPAS IO Error: Unrecognized error code...', MPAS_LOG_ERR)
65036543
end select

src/framework/mpas_io_types.inc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@
6565
MPAS_IO_ERR_UNIMPLEMENTED = -18, &
6666
MPAS_IO_ERR_WOULD_CLOBBER = -19, &
6767
MPAS_IO_ERR_NOEXIST_READ = -20, &
68-
MPAS_IO_ERR_MISSING_DIM = -21
68+
MPAS_IO_ERR_MISSING_DIM = -21, &
69+
MPAS_IO_ERR_INSUFFICIENT_BUF = -22
6970

7071
type MPAS_IO_Handle_type
7172
logical :: initialized = .false.

0 commit comments

Comments
 (0)