Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Sourced allocation memory leak

Ferdinand_T_
New Contributor II
460 Views

Hello!

The program below allocates a polymorphic derived type variable from a SOURCE expression in ALLOCATE statement. The SOURCE itself becomes allocated as a result of a function call with allocatable return type. This seemingly causes the allocation of the source's derived type components to get lost in a memory leak.

If you know what is going on here, I would appreciate your help!

[fortran]

module m
    implicit none
 
    type :: derived_type
    ! causes 8 bit memory leak per allocation
        integer(8), allocatable :: alloc_comp              ! (*)
    end type
contains
 
    ! function with allocatable polymorphic result
    function make_class()
        class(derived_type), allocatable :: make_class     ! (**)
 
        allocate(make_class)
 
        ! this allocation apparently gets lost
        allocate(make_class%alloc_comp)
    end function
end module
 
program p
    use m
    implicit none
    integer :: ii
 
    ! multiply leak by number of itterations
    do ii = 1,10
         call cause_mem_leak()
    end do
contains
 
    ! assign allocatable polymorphic function result to local variable
    subroutine cause_mem_leak()
        class(derived_type), allocatable :: my_class
 
        ! source expression gets allocated inside the allocation statement
        allocate(my_class, source = make_class())
 
        ! no help here:
        deallocate(my_class%alloc_comp)
        deallocate(my_class)
    end subroutine
end program
[/fortran]


Results:

Valgrind detects 80 bit memory leak on my unix 64 bit Intel® Core™2 Quad CPU Q9400 @ 2.66GHz × 4 system.


Variations:

  •  (*)  change to pointer here, and everything is fine.
  • (**) change to type here and get a runtime crash:
          "forrtl: severe (153): allocatable array or pointer is not allocated"
  • However, both changes made simultaneously bring back the leak again.
  • Also, changing all 'class' into 'type' (e.g. pre-F2003 standard) solves all problems.

 My Question:

Allocating the SOURCE expression inside an ALLOCATE statement. The intel docs say:

"If [..] source-expr is specified, it must not be allocated in the ALLOCATE statement in which it appears"

The expression 'make_class()', which triggers the allocation of the SOURCE, is part of the ALLOCATE statement.
However, the actual allocation of the SOURCE is done by second, nested ALLOCATE statement inside the 'make_class()' function.

Does that still make the code invalid?

If so, what is the Fortran way to assign an allocatable polymorphic function result to a variable?
(Without the "realloc-lhs in assignment to polymorphic" F2008 feature)?

Thank you, with regards

Ferdinand

0 Kudos
3 Replies
Izaak_Beekman
New Contributor II
460 Views

Regarding your last question, I have wondered the same thing, and put that question to the comp.lang.fortran newsgroup. You can see the thread here: https://groups.google.com/forum/#!searchin/comp.lang.fortran/zaak/comp.lang.fortran/i_4xy9RtJAU/EETjD4jZQe0J

It is my understanding that you either need to use defined assignment to wrap a sourced allocation to achieve this with a F2003 compiler, however, it may not be wise to do so with F2008 on the horizon. Users who read a sourced allocation directly are less likely to be confused once F2008 is common, including polymorphic realloc_lhs. Note that copy/assignment(=) cannot be type bound in order for this to work.

[fortran]  
generic :: assignment(=) => copy 
contains
subroutine copy(lhs,rhs) 
     CLASS(my_abstract), INTENT(OUT), ALLOCATABLE :: lhs 
     CLASS(my_abstract), INTENT(IN) :: rhs 
     ALLOCATE(lhs, SOURCE=rhs) 
end subroutine [/fortran]

0 Kudos
Ferdinand_T_
New Contributor II
460 Views

Hi Zaak,

thanks for pointing to your informative newsgroup thread! I share your opinion in that a sourced allocation should be prefered over a defined assignment (e.g. hiding the allocate statement behind a '=' sign, hence pure (& obscure!) cosmetic) until F2008 polymorphic realloc_lhs is supported.

However, I tested the defined assignment approach with my sample program, but valgrind still detects a memory leak (ifort 14.0.1).

[fortran]

module m
    implicit none
 
    type :: derived_type
        ! causes 8 bit memory leak per allocation
        integer(8), allocatable :: alloc_comp            ! (*)
    end type
 
    ! NEW: defined assignment to emulate polymorphic realloc_lhs
    interface assignment(=)
        module procedure copy
    end interface
contains
 
    ! function with allocatable polymorphic result
    function make_class()
       class(derived_type), allocatable :: make_class    ! (**)
 
       allocate(make_class)
 
       ! this allocation apparently gets lost
       allocate(make_class%alloc_comp)
    end function
 
    ! NEW: emulate polymorphic realloc_lhs
    subroutine copy(lhs, rhs)
        ! both lhs and rhs can be polymorphic
        class(derived_type), allocatable, intent(out) :: lhs
        class(derived_type), intent(in) :: rhs
 
        allocate(lhs, source = rhs)
    end subroutine
end module
 
program p
    use m
    implicit none
    integer :: ii
 
    ! multiply leak by number of itterations
    do ii = 1,10
         call cause_mem_leak()
    end do
contains
 
    ! assign allocatable polymorphic function result to local variable
    subroutine cause_mem_leak()
        class(derived_type), allocatable :: my_class
 
        ! source expression gets allocated inside the allocation statement
        ! allocate(my_class, source = make_class())
 
        ! NEW: try it with the defined assignment
        my_class = make_class()
 
        ! no help here:
        deallocate(my_class%alloc_comp)
        deallocate(my_class)
   end subroutine
end program

! NEW: changes to original sample program
! RESULTS: unchanged, e.g. still 80 bit memory leak

[/fortran]

No compiler flags where used, and valgrind --tool=memcheck ./a.out says:

==4063== LEAK SUMMARY:
==4063==    definitely lost: 80 bytes in 10 blocks
==4063==    indirectly lost: 0 bytes in 0 blocks
==4063==      possibly lost: 0 bytes in 0 blocks
==4063==    still reachable: 32 bytes in 1 blocks
==4063==         suppressed: 0 bytes in 0 blocks

Best reagrds,

Ferdinand

0 Kudos
Izaak_Beekman
New Contributor II
460 Views

I'm not entirely sure whether or not your code is standards conforming, but I think it is. Hopefully someone with a more intimate understanding with the standards can take a look at it.

Thanks for sharing your results!

0 Kudos
Reply