Fortran function returning unallocated array causes segmentation fault

邮差的信 提交于 2019-12-11 00:29:08

问题


I'm struggling with some Modern Fortran wrappers to some MPI scatter/gather routines. I am trying to have a wrapper interface that only has an array on input and returns the MPI-operated result on output, for several derived types, doing something like this:

type(mytype), allocatable :: chunk(:),whole(:)

! [...] chunk descends from previous parts of the code

! Get global array
whole = gatherv(array=chunk,receiver_node=cpuid)

I'm doing this using functions that return allocatable arrays. However, I'm getting segmentation fault on both gcc 6.2.0 and gcc 7.1.0 whenever I return a non-allocated result.

The reason I need a non-allocated result is that sometimes I need to gather the whole array only on a specified CPU, so I don't want to waste memory on all other nodes: the receiver node returns an allocated array with the data, and all other nodes receive an empty and deallocated array.

This is sample code that reproduces the issue:

program test_allocatable_fun
    implicit none

    integer, allocatable :: my_array(:)
    integer :: n

    n = 3; my_array = unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
    n =-3; my_array = unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
    n = 5; my_array = unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
    n = 0; my_array = unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)

    return


    contains

    function unallocated_array(n) result(array)
        integer, intent(in) :: n
        integer, allocatable :: array(:)
        integer :: j
        if (n>0) then
            allocate(array(n))
            array(:) = [(j,j=1,n)]
        else
            if (allocated(array)) deallocate(array)
        end if
    end function unallocated_array

end program test_allocatable_fun

The segmentation fault happens at the assignment line, i.e.:

my_array = unallocated_array(n)

Has any of you had the same issue before? Or, am I violating anything in the standard? I can't see why a function returning an allocatable array should be forced to have the return value allocated. Isn't it the same as having an intent(out) dummy variable in a subroutine?


回答1:


A function result is not the same as a dummy argument with the intent(out) attribute. It differs in a significant way here in that a non-pointer function result must always be defined when execution of the function terminates. This is covered by Fortran 2008 12.6.2.2 p4.

It is necessary, but not sufficient, for an allocatable function result (any object) to be allocated to be defined.

To some extent you can consider this in the way that a function result is always referenced (otherwise the function wouldn't be executed). An actual argument not defined may also not be referenced, but such referencing wouldn't be "automatic".

As mentioned in comments, the function result may be allocated to be an array of size zero. Zero-sized arrays are always of defined value.

You can see some comparison of zero-sized arrays and not-allocated arrays in this other question.




回答2:


I suspect any allocatable array in a main program contains data of a global nature. I usually put such variables in a module. This way this variable does not need to be passed around and can be allocated and deallocated in the main program, subroutines, and/or functions.

Since the array is the only return value, I changed it to a subroutine. How does this work for you? P.S. 'implicit none' should be in every module, program, function, and subroutine.

module fun
   implicit none
   integer, allocatable :: my_array(:)
end module fun

program test_allocatable_fun
   use fun
   implicit none

   integer :: n

   n = 3; call unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
   n =-3; call unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
   n = 5; call unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)
   n = 0; call unallocated_array(n); print *, 'n=',n,' allocated(array)=',allocated(my_array)

   return

   contains

subroutine unallocated_array(n)

    use fun
    implicit none

    integer, intent(in) :: n
    integer :: j
    if (n>0) then
        allocate(my_array(n))
        my_array(:) = [(j,j=1,n)]
    else
        if (allocated(my_array)) deallocate(my_array)
    end if
end subroutine unallocated_array

end program test_allocatable_fun


来源:https://stackoverflow.com/questions/48155025/fortran-function-returning-unallocated-array-causes-segmentation-fault

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!