Search code examples
functionfortrangfortranfortran2003allocatable-array

Fortran function returning unallocated array causes segmentation fault


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?


Solution

  • 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.