diff --git a/msvs/mf6core.vfproj b/msvs/mf6core.vfproj
index 173962bf69b..188c714e9b6 100644
--- a/msvs/mf6core.vfproj
+++ b/msvs/mf6core.vfproj
@@ -549,7 +549,7 @@
-
+
diff --git a/src/Utilities/Memory/Memory.f90 b/src/Utilities/Memory/Memory.F90
similarity index 79%
rename from src/Utilities/Memory/Memory.f90
rename to src/Utilities/Memory/Memory.F90
index 5d4d6363f12..1799559ef0b 100644
--- a/src/Utilities/Memory/Memory.f90
+++ b/src/Utilities/Memory/Memory.F90
@@ -29,7 +29,10 @@ module MemoryTypeModule
logical(LGP), pointer :: logicalsclr => null() !< pointer to the logical
integer(I4B), pointer :: intsclr => null() !< pointer to the integer
real(DP), pointer :: dblsclr => null() !< pointer to the double
- character(len=:), dimension(:), pointer, contiguous :: astr1d => null() !< pointer to the 1d character string array
+ ! The 1d character string array is handled differently than the other arrays due to a bug in gfortran 11.3 and 12.1.
+ ! Due to this bug the length of the string is not stored in the array descriptor. With a segmentation fault as a result
+ ! on deallocation.
+ class(*), dimension(:), pointer, contiguous :: astr1d => null() !< pointer to the 1d character string array
integer(I4B), dimension(:), pointer, contiguous :: aint1d => null() !< pointer to 1d integer array
integer(I4B), dimension(:, :), pointer, contiguous :: aint2d => null() !< pointer to 2d integer array
integer(I4B), dimension(:, :, :), pointer, contiguous :: aint3d => null() !< pointer to 3d integer array
@@ -98,8 +101,12 @@ function mt_associated(this) result(al)
end function mt_associated
subroutine mt_deallocate(this)
+ use iso_c_binding, only: c_loc, c_ptr, c_null_ptr, c_f_pointer
class(MemoryType) :: this
integer(I4B) :: n
+ type(c_ptr) :: cptr
+
+ character(len=1), dimension(:), pointer :: astr1d
if (associated(this%strsclr)) then
if (this%master) deallocate (this%strsclr)
@@ -121,8 +128,30 @@ subroutine mt_deallocate(this)
nullify (this%dblsclr)
end if
+ ! Handle the dealloction of the 1d character string array differently due to a bug in gfortran 11.3, 12.1, 13.1 and 13.2.
+ ! Due to a bug in the gfortran compiler we can't use a deferred length character variable
+ ! https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106317
+ !
+ ! We use a c_ptr to cast the pointer to a string array with a length of 1. The actual length of the array is
+ ! computed by the actual length of the string multiplied by the array size.
+ ! So we go from the actual character(len=element_size), dimension(isize) to a character(len=1), dimension(isize*element_size).
+
if (associated(this%astr1d)) then
+ select type (item => this%astr1d)
+ type is (character(*))
+ cptr = c_loc(item)
+ class default
+ cptr = c_null_ptr
+ end select
+
+ call c_f_pointer(cptr, astr1d, [this%isize * this%element_size])
+
+#if __GFORTRAN__ && ((__GNUC__ < 13) || (__GNUC__ == 13 && __GNUC_MINOR__ < 3))
+ if (this%master) deallocate (astr1d)
+#else
if (this%master) deallocate (this%astr1d)
+#endif
+
nullify (this%astr1d)
end if
diff --git a/src/Utilities/Memory/MemoryManager.f90 b/src/Utilities/Memory/MemoryManager.f90
index b8083e54213..367fcdc61c7 100644
--- a/src/Utilities/Memory/MemoryManager.f90
+++ b/src/Utilities/Memory/MemoryManager.f90
@@ -484,9 +484,7 @@ subroutine allocate_str1d(astr1d, ilen, nrow, name, mem_path)
allocate (mt)
!
! -- set memory type
- ! this does not work with gfortran 11.3 and 12.1
- ! so we have to disable the pointing to astr1d
- ! mt%astr1d => astr1d
+ mt%astr1d => astr1d
mt%element_size = ilen
mt%isize = isize
mt%name = name
@@ -1162,6 +1160,7 @@ subroutine reallocate_str1d(astr, ilen, nrow, name, mem_path)
deallocate (astrtemp)
!
! -- reset memory manager values
+ mt%astr1d => astr
mt%element_size = ilen
mt%isize = isize
mt%nrealloc = mt%nrealloc + 1
@@ -1596,7 +1595,12 @@ subroutine setptr_str1d(astr1d, name, mem_path)
logical(LGP) :: found
! -- code
call get_from_memorystore(name, mem_path, mt, found)
- astr1d => mt%astr1d
+ select type (item => mt%astr1d)
+ type is (character(*))
+ astr1d => item
+ class default
+ astr1d => null()
+ end select
end subroutine setptr_str1d
!> @brief Set pointer to an array of CharacterStringType
@@ -1937,35 +1941,8 @@ subroutine deallocate_str1d(astr1d, name, mem_path)
character(len=*), dimension(:), pointer, contiguous, intent(inout) :: astr1d !< array of strings
character(len=*), optional, intent(in) :: name !< variable name
character(len=*), optional, intent(in) :: mem_path !< path where variable is stored
- ! -- local
- type(MemoryType), pointer :: mt
- logical(LGP) :: found
- type(MemoryContainerIteratorType), allocatable :: itr
! -- code
- !
- found = .false.
- if (present(name) .and. present(mem_path)) then
- call get_from_memorystore(name, mem_path, mt, found)
- nullify (mt%astr1d)
- else
- itr = memorystore%iterator()
- do while (itr%has_next())
- call itr%next()
- mt => itr%value()
- if (associated(mt%astr1d, astr1d)) then
- found = .true.
- exit
- end if
- end do
- end if
-
- if (found) then
- if (mt%master) then
- deallocate (astr1d)
- else
- nullify (astr1d)
- end if
- end if
+ return
end subroutine deallocate_str1d
@@ -2461,7 +2438,6 @@ end function calc_virtual_mem
subroutine mem_da()
! -- modules
use VersionModule, only: IDEVELOPMODE
- use InputOutputModule, only: UPCASE
! -- local
class(MemoryType), pointer :: mt
type(MemoryContainerIteratorType), allocatable :: itr
@@ -2471,6 +2447,7 @@ subroutine mem_da()
call itr%next()
mt => itr%value()
call mt%mt_deallocate()
+ if (IDEVELOPMODE == 1) call mem_da_check(mt)
deallocate (mt)
end do
@@ -2480,6 +2457,39 @@ subroutine mem_da()
end if
end subroutine mem_da
+ subroutine mem_da_check(mt)
+ ! -- modules
+ use InputOutputModule, only: UPCASE
+ ! -- dummy
+ class(MemoryType), pointer :: mt
+ ! -- local
+ character(len=LINELENGTH) :: error_msg
+ character(len=LENVARNAME) :: ucname
+ !
+ ! -- check if memory has been deallocated
+ if (mt%mt_associated() .and. mt%element_size == -1) then
+ error_msg = trim(adjustl(mt%path))//' '// &
+ trim(adjustl(mt%name))//' has invalid element size'
+ call store_error(trim(error_msg))
+ end if
+ !
+ ! -- check if memory has been deallocated
+ if (mt%mt_associated() .and. mt%isize > 0) then
+ error_msg = trim(adjustl(mt%path))//' '// &
+ trim(adjustl(mt%name))//' not deallocated'
+ call store_error(trim(error_msg))
+ end if
+ !
+ ! -- check case of varname
+ ucname = mt%name
+ call UPCASE(ucname)
+ if (mt%name /= ucname) then
+ error_msg = trim(adjustl(mt%path))//' '// &
+ trim(adjustl(mt%name))//' not upper case'
+ call store_error(trim(error_msg))
+ end if
+ end subroutine mem_da_check
+
!> @brief Create a array with unique first components from all memory paths.
!! Only the first component of the memory path is evaluated.
!<
diff --git a/src/meson.build b/src/meson.build
index beb5a53dd0f..440072651e3 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -349,7 +349,7 @@ modflow_sources = files(
'Utilities' / 'Idm' / 'netcdf' / 'NCFileVars.f90',
'Utilities' / 'Matrix' / 'MatrixBase.f90',
'Utilities' / 'Matrix' / 'SparseMatrix.f90',
- 'Utilities' / 'Memory' / 'Memory.f90',
+ 'Utilities' / 'Memory' / 'Memory.F90',
'Utilities' / 'Memory' / 'MemoryHelper.f90',
'Utilities' / 'Memory' / 'MemoryContainerIterator.f90',
'Utilities' / 'Memory' / 'MemoryStore.f90',
diff --git a/utils/mf5to6/msvs/mf5to6.vfproj b/utils/mf5to6/msvs/mf5to6.vfproj
index 1d2c110b6a9..ec4d6f0eab0 100644
--- a/utils/mf5to6/msvs/mf5to6.vfproj
+++ b/utils/mf5to6/msvs/mf5to6.vfproj
@@ -82,7 +82,7 @@
-
+
diff --git a/utils/mf5to6/pymake/extrafiles.txt b/utils/mf5to6/pymake/extrafiles.txt
index 34533a24d27..a371e9d8a9a 100644
--- a/utils/mf5to6/pymake/extrafiles.txt
+++ b/utils/mf5to6/pymake/extrafiles.txt
@@ -1,4 +1,4 @@
-../../../src/Utilities/Memory/Memory.f90
+../../../src/Utilities/Memory/Memory.F90
../../../src/Utilities/Memory/MemoryContainerIterator.f90
../../../src/Utilities/Memory/MemoryHelper.f90
../../../src/Utilities/Memory/MemoryManager.f90