-
Notifications
You must be signed in to change notification settings - Fork 383
Ensure the buffer provided to MPAS_io_get_var_generic is large enough. #1367
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
jim-p-w
wants to merge
5
commits into
MPAS-Dev:develop
Choose a base branch
from
jim-p-w:atmosphere/check_buffer_len
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+272
−14
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
3909575
Ensure the buffer provided to MPAS_io_get_var_generic is large enough.
jim-p-w 7f2f3a8
Modifications per PR suggestions:
jim-p-w df2646a
modifications per PR comments:
jim-p-w 8e07d56
Modifications per PR comments:
jim-p-w 293caea
changes re PR comments
jim-p-w File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,203 @@ | ||
| ! Copyright (c) 2025 The University Corporation for Atmospheric Research (UCAR). | ||
| ! | ||
| ! Unless noted otherwise source code is licensed under the BSD license. | ||
| ! Additional copyright and license information can be found in the LICENSE file | ||
| ! distributed with this code, or at https://mpas-dev.github.io/license.html . | ||
| ! | ||
| module test_core_io | ||
|
|
||
| #define ERROR_WRITE(M) call mpas_log_write( M , messageType=MPAS_LOG_ERR) | ||
| #define ERROR_WRITE_ARGS(M, ARGS) call mpas_log_write( M , ARGS, messageType=MPAS_LOG_ERR) | ||
| use mpas_log | ||
| use mpas_io | ||
|
|
||
| implicit none | ||
| private | ||
| public :: test_core_io_test | ||
|
|
||
| contains | ||
|
|
||
| !*********************************************************************** | ||
| ! | ||
| ! routine close_file_with_message | ||
| ! | ||
| !> \brief closes the provided file handle and writes an error message. | ||
| !----------------------------------------------------------------------- | ||
| subroutine close_file_with_message(fileHandle, message, args) | ||
| type(MPAS_IO_Handle_type), intent(inout) :: fileHandle | ||
| character (len=*), intent(in), optional :: message | ||
| integer, dimension(:), intent(in), optional :: args | ||
|
|
||
| integer :: local_ierr | ||
|
|
||
| ! log an error message | ||
| if (present(message)) then | ||
| if (present(args)) then | ||
| ERROR_WRITE_ARGS(message, intArgs=args) | ||
| else | ||
| ERROR_WRITE(message) | ||
| end if | ||
| end if | ||
|
|
||
| ! close the provided file | ||
| call MPAS_io_close(fileHandle, local_ierr) | ||
| if (local_ierr /= MPAS_IO_NOERR) then | ||
| ERROR_WRITE_ARGS('MPAS_io_close failed with error code:$i', intArgs=(/local_ierr/)) | ||
| return | ||
| endif | ||
|
|
||
| end subroutine close_file_with_message | ||
|
|
||
| !*********************************************************************** | ||
| ! | ||
| ! routine test_read_string_buffer_check | ||
| ! | ||
| !> \brief verifies attempts to read strings into buffers which are too small | ||
| !> to hold the value fails safely. | ||
| !> \details | ||
| !> Run these tests with valgrind to ensure there are no buffer overflows when | ||
| !> attempting to read strings into undersized buffers. | ||
| !----------------------------------------------------------------------- | ||
| subroutine test_read_string_buffer_check(domain, ierr) | ||
|
|
||
| type (domain_type), intent(inout) :: domain | ||
| integer, intent(out) :: ierr | ||
|
|
||
| integer :: local_ierr, i | ||
| type(MPAS_IO_Handle_type) :: fileHandle | ||
| character (len=StrKIND), dimension(1), parameter :: dimNamesString = ['StrLen'] | ||
| character (len=StrKIND), dimension(2), parameter :: dimNamesStringTime = ['StrLen', 'Time '] | ||
| character (len=32), parameter :: varName1 = 'stringVar' | ||
| character (len=32), parameter :: varName2 = 'stringTimeVar' | ||
| character (len=*), parameter :: varValue1 = 'This is a string' | ||
| character (len=32), dimension(2), parameter :: varNames = [varName1, varName2] | ||
| integer, parameter :: bufferSize=128 | ||
| integer, parameter :: smallBufferSize=bufferSize/2 | ||
| character (len=bufferSize) :: buffer | ||
| character (len=smallBufferSize) :: smallBuffer | ||
| character (len=*), parameter :: filename = 'char_data.nc' | ||
|
|
||
| ierr = 0 | ||
|
|
||
| ! open a file to write char variables to | ||
| fileHandle = MPAS_io_open(filename, MPAS_IO_WRITE, MPAS_IO_NETCDF4, domain % ioContext, & | ||
| clobber_file=.true., truncate_file=.true., ierr=local_ierr) | ||
| if (local_ierr /= MPAS_IO_NOERR) then | ||
| ierr = 1 | ||
| ERROR_WRITE('Error opening file ' // trim(filename)) | ||
| return | ||
| end if | ||
|
|
||
| ! define dimensions and char variables | ||
| call MPAS_io_def_dim(fileHandle, dimNamesStringTime(1), bufferSize, local_ierr) | ||
| if (local_ierr /= MPAS_IO_NOERR) then | ||
| ierr = 1 | ||
| call close_file_with_message(fileHandle, 'Error defining '//trim(dimNamesStringTime(1))//', error=$i', (/local_ierr/)) | ||
| return | ||
| end if | ||
| call MPAS_io_def_dim(fileHandle, dimNamesStringTime(2), MPAS_IO_UNLIMITED_DIM, local_ierr) | ||
| if (local_ierr /= MPAS_IO_NOERR) then | ||
| ierr = 1 | ||
| call close_file_with_message(fileHandle, 'Error defining '//trim(dimNamesStringTime(2))//', error=$i', (/local_ierr/)) | ||
| return | ||
| end if | ||
| call MPAS_io_def_var(fileHandle, varNames(1), MPAS_IO_CHAR, dimNamesString, ierr=local_ierr) | ||
| if (local_ierr /= MPAS_IO_NOERR) then | ||
| ierr = 1 | ||
| call close_file_with_message(fileHandle, 'Error defining var "'//trim(varNames(1))//'" error=$i', (/local_ierr/)) | ||
| return | ||
| end if | ||
| call MPAS_io_def_var(fileHandle, varNames(2), MPAS_IO_CHAR, dimNamesStringTime, ierr=local_ierr) | ||
| if (local_ierr /= MPAS_IO_NOERR) then | ||
| ierr = 1 | ||
| call close_file_with_message(fileHandle, 'Error defining var "'//trim(varNames(2))//'" error=$i', (/local_ierr/)) | ||
| return | ||
| end if | ||
|
|
||
| ! write the string values | ||
| do i=1,size(varNames) | ||
| call MPAS_io_put_var_char0d(fileHandle, varNames(i), varValue1, local_ierr) | ||
| if (local_ierr /= MPAS_IO_NOERR) then | ||
| ierr = 1 | ||
| call close_file_with_message(fileHandle, 'Error writing "'//trim(varNames(i))// & | ||
| '", error=$i', (/local_ierr/)) | ||
| return | ||
| end if | ||
|
|
||
| ! verify the strings are read into buffers which are large enough for the string values | ||
| call MPAS_io_get_var_char0d(fileHandle, varNames(i), buffer, local_ierr) | ||
| if (local_ierr /= MPAS_IO_NOERR) then | ||
| ierr = 1 | ||
| call close_file_with_message(fileHandle, 'Error reading "'//trim(varNames(i))// & | ||
| '", error=$i', (/local_ierr/)) | ||
| return | ||
| end if | ||
| end do | ||
|
|
||
| ! verify attempts to read strings into buffers which are too small generates an error | ||
| call mpas_log_write(' ') | ||
| call mpas_log_write('Expect to see the following error:') | ||
| call MPAS_io_err_mesg(domain % ioContext, MPAS_IO_ERR_INSUFFICIENT_BUF, .false.) | ||
| call mpas_log_write(' ') | ||
| do i=1,size(varNames) | ||
| ! this should return an error | ||
| call MPAS_io_get_var_char0d(fileHandle, varNames(i), smallBuffer, local_ierr) | ||
| call mpas_log_write(' ') | ||
|
|
||
| if (local_ierr /= MPAS_IO_ERR_INSUFFICIENT_BUF) then | ||
| ierr = 1 | ||
| if (local_ierr == MPAS_IO_NOERR) then | ||
| call close_file_with_message(fileHandle, 'Expected MPAS_IO_ERR_INSUFFICIENT_BUF ($i)'& | ||
| //' but recieved no error reading "'//trim(varName1), (/local_ierr/)) | ||
| else | ||
| call close_file_with_message(fileHandle, 'Expected MPAS_IO_ERR_INSUFFICIENT_BUF ($i)'& | ||
| //' but recieved error $i reading "'//trim(varName1)//'"', & | ||
| (/MPAS_IO_ERR_INSUFFICIENT_BUF, local_ierr/)) | ||
| end if | ||
| return | ||
| end if | ||
| end do | ||
| call close_file_with_message(fileHandle) | ||
|
|
||
| end subroutine test_read_string_buffer_check | ||
|
|
||
|
|
||
| !*********************************************************************** | ||
| ! Subroutine test_core_io_test | ||
| ! | ||
| !> \brief Core test suite for I/O | ||
| !> | ||
| !> \details This subroutine tests mpas_io features. | ||
| !> It calls individual tests for I/O operations. | ||
| !> See the subroutine body for details. | ||
| !> The results of each test are logged with a success or failure message. | ||
| !> | ||
| !> \param domain The domain object that contains the I/O context | ||
| !> \param ierr The error code that indicates the result of the test. | ||
| ! | ||
| !----------------------------------------------------------------------- | ||
| subroutine test_core_io_test(domain, ierr) | ||
|
|
||
| use mpas_log | ||
|
|
||
| type (domain_type), intent(inout) :: domain | ||
| integer, intent(out) :: ierr | ||
|
|
||
| integer :: test_status | ||
|
|
||
| ierr = 0 | ||
| test_status = 0 | ||
|
|
||
| call mpas_log_write('Testing char-0 buffer reads') | ||
| call test_read_string_buffer_check(domain, test_status) | ||
| if (test_status == 0) then | ||
| call mpas_log_write('char-0 buffer tests: SUCCESS') | ||
| else | ||
| call mpas_log_write('char-0 buffer tests: FAILURE', MPAS_LOG_ERR) | ||
| ierr = ierr + abs(test_status) | ||
| end if | ||
|
|
||
|
|
||
| end subroutine test_core_io_test | ||
|
|
||
| end module test_core_io |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.