Search code examples
memory-leaksfortrangfortranintel-fortrannag-fortran

Memory leak in the assignment using Intel Fortran compiler


Consider the following minimal working example:

module lib
    type FG_t
        real,allocatable::g(:)
    contains
        procedure,private::FG_Assign
        generic::assignment(=)=>FG_Assign
    end type
    interface operator(-)
        procedure FG_Sub
    end interface
contains
    elemental subroutine FG_Assign(this,that)
        class(FG_t),intent(inout)::this
        class(FG_t),intent(in)::that
        this%g=that%g
    end
    elemental type(FG_t) function FG_Sub(this,that)
        class(FG_t),intent(in)::this
        real,intent(in)::that
        FG_Sub=FG_t(this%g-that)
    end
end

program prog
    use lib
    type(FG_t)::arr(1000),arr_(SIZE(arr))
    do i=1,SIZE(arr)
        allocate(arr(i)%g(10))
    end do
    do i=1,100000
        arr_=arr-1.
    end do
end

When running the executable generated from the code with ifx (2022.2.1), ifort (2021.7.1), nvfortran (22.9), or nagfor (7.1), memory fills rapidly (which can lead to your PC crashing in the case of a higher number of iterations). Memory vs time:

memory vs time

Using gfortran (11.1.0) or replacing elemental before FG_assign with pure fixes the problem for my version of Intel compiler (but not for the Nvidia and NAG compilers). However, the elemental keyword is used for assignment in a similar context in the code of Fortran stdlib.

Intel VTune Profiler shows that most of the memory is allocated in the line this%g=that%g after FG_Sub is called in the line arr_=arr-1..

What is the reason for this compiler-dependent problem, and is there a way to avoid it?


Solution

  • It appears to be a compiler bug. Intel, Nvidia, and NAG responded and filed bug reports for this issue. Their IDs are CMPLRLLVM-44748 (Intel) and TPR #33180 (Nvidia).

    This issue can be avoided by removing the elemental keyword before FG_Assign or by iterating over the elements of arrays (so that the elemental property of FG_Assign won't be used). For the second solution arr_=arr-1. should be replaced with

    do k=1,SIZE(arr)
        arr_(k)=arr(k)-1.
    end do