Hi,
We’ve run into some problems trying to get addresses of elements in character arrays. The below program is the driver
program repro1_dangling
use fms_string_utils_repro_mod, only: fms_array_to_pointer
use iso_c_binding, only: c_ptr, c_loc, c_null_char, c_intptr_t, c_f_pointer, c_char
implicit none
character(len=255), allocatable, target :: names(:)
type(c_ptr), allocatable :: ptrs(:)
integer(c_intptr_t) :: got, expect
integer :: i
logical :: dangling
character(kind=c_char), pointer :: cptr_char
! initialize strings
allocate(names(3))
names(1) = "alpha"//c_null_char
names(2) = "beta"//c_null_char
names(3) = "gamma"//c_null_char
! problematic helper returns wrong pointers
ptrs = fms_array_to_pointer(names)
! check collected addresses with expected addresses
dangling = .false.
do i = 1, size(names)
got = transfer(ptrs(i), 0_c_intptr_t)
expect = transfer(c_loc(names(i)), 0_c_intptr_t)
print *, "i =", i, " returned ptr =", got, " address of names(i) =", expect
if (got /= expect) dangling = .true.
end do
if (dangling) then
print *, "BUG: fms_array_to_pointer pointers do not alias names(:) -> dangling"
else
print *, "OK: pointers alias names(:)"
end if
flush(6)
! Dereference the (bad) pointers -> reads through mis-strided/dangling addresses.
do i = 1, size(names)
call c_f_pointer(ptrs(i), cptr_char)
print *, "first char via returned ptr, i =", i, " -> ", cptr_char
end do
end program repro1_dangling
and the following is the corresponding module.
module fms_string_utils_repro_mod
use, intrinsic :: iso_c_binding, only: c_ptr, c_loc
implicit none
private
public :: fms_array_to_pointer
contains
!> Verbatim copy of FMS string_utils/fms_string_utils.F90::fms_array_to_pointer
function fms_array_to_pointer(my_array) result(my_pointer)
character(len=*), target :: my_array(:) !< Array of strings to convert
type(c_ptr), allocatable :: my_pointer(:)
integer :: i
if (allocated(my_pointer)) stop "my_pointer already allocated"
allocate(my_pointer(size(my_array)))
do i = 1, size(my_array)
my_pointer(i) = c_loc(my_array(i))
enddo
end function fms_array_to_pointer
end module fms_string_utils_repro_mod
Running it gives me output like:
i = 1 returned ptr = 367289024
address of names(i) = 367289024
i = 2 returned ptr = 367321792
address of names(i) = 367289279
i = 3 returned ptr = 367354560
address of names(i) = 367289534
BUG: fms_array_to_pointer pointers do not alias names(:) -> dangling
first char via returned ptr, i = 1 -> a
first char via returned ptr, i = 2 ->
first char via returned ptr, i = 3 ->
The problem being that the addresses produced by the helper function don’t match what is collected outside the helper.
Notably, compiling the module inside the same file as the driver gives the correct result. So to reproduce the wrong result, ensure that the module and the driver program are in separate files.
This code seems to be ok for intel + gnu compilers.
I don’t know much about C-Fortran interop, so not sure if this is well-defined behaviour.