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

ifort generating leaky code?

Izaak_Beekman
New Contributor II
751 Views

Caveat: My understanding of the F2003, F2008 allocatable function results and scalars as derived type components is a little bit hazy, but I am pretty sure that the following code is F2008 compliant.  Please correct me, and tell my where I've run amuck if that is not the case. Here is a simple test program:

[fortran]

module stringbug
implicit none
private
public :: string_t
type :: string_t
private
character(:) ,allocatable :: string
contains
procedure :: ConcatChars
procedure :: Assign
procedure :: AssignChars
procedure :: Get
generic :: operator(//) => ConcatChars
generic :: assignment(=) => Assign ,AssignChars
end type
interface string_t
procedure :: StringConstructor
end interface
contains
function StringConstructor(string) result(res)
character(*) ,intent(in) :: string
type(string_t) :: res
! allocate(res)
res%string = string
end function
subroutine Assign(lhs,rhs)
class(string_t) ,intent(inout) :: lhs
class(string_t) ,intent(in) :: rhs
lhs%string = rhs%string
end subroutine
subroutine AssignChars(lhs,rhs)
class(string_t) ,intent(inout) :: lhs
character(*) ,intent(in) :: rhs
lhs%string = rhs
end subroutine
function ConcatChars(lhs,rhs) result(res)
class(string_t) ,intent(in) :: lhs
character(*) ,intent(in) :: rhs
class(string_t) ,allocatable :: res
allocate(res,mold=lhs)
res%string = lhs%string // rhs ! This leaks
end function
function Get(this) result(res)
class(string_t) ,intent(in) :: this
character(:) ,allocatable :: res
res = this%string
end function
end module
program memleak
use stringbug, only: string_t
implicit none
class(string_t) ,allocatable :: testvar

allocate(string_t :: testvar)
testvar = 'foobar'
testvar = string_t('mystring')
print*, testvar%Get()
testvar = testvar // 'baz' ! this leaks
testvar = testvar%ConcatChars('bip') ! this does too.
print*, testvar%Get()
end program

[/fortran]

The code generated by

[bash] 

$ ifort -V
Intel(R) Fortran Intel(R) 64 Compiler XE for applications running on Intel(R) 64, Version 13.1.0.146 Build 20130121 [/bash]

seems to leak at line 41 in ConcatChars (which is being called via the overloaded operator //)

The code was compiled as:

[bash]$ ifort -g -O0 -assume realloc_lhs -o memleak bug.f90[/bash] on a RHEL 5 x86_64 machine and the leak was found via [bash]$ valgrind --leak-check ./memleak[/bash] The valgrind output is attached.

I think this might be a compiler bug.

Thanks,

0 Kudos
4 Replies
jimdempseyatthecove
Honored Contributor III
751 Views

I think Steve Lionel might be able to recall a similar issue where a temporary was created on the right side in A = B + C, or was it A = fn(B + C). I think the issue was the array temporary was not reclaimed.

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
751 Views

I can reproduce this and have escalated it to the developers as issue DPD200244704. Thanks for reporting it.

0 Kudos
Izaak_Beekman
New Contributor II
751 Views

jimdempseyatthecove wrote:

I think Steve Lionel might be able to recall a similar issue where a temporary was created on the right side in A = B + C, or was it A = fn(B + C). I think the issue was the array temporary was not reclaimed.

Jim Dempsey

Jim and Steve,

Thanks for the response.

Jim: The case where A = fn(B + C) is a particularly challenging one to implement in a leak free manner, and AFAIK, it necessitates reference counting to implement. My example code is similar to this, as the assignment operator has been overloaded to accomodate type extended polymorphic variables. So the leaky line looks like A = B // C but it is effectively equivalent to CALL Assign( A, (B // C) ) where the first argument to Assign is intent(inout) and the second argument is intent(in)

0 Kudos
jimdempseyatthecove
Honored Contributor III
751 Views

Zaak,

You do not need reference counting on the (B//C). The compiler knows there is only one refference and that the reference lifetime expires at the end of the statement (where it can be destroyed). Note, the CALL Assign second argument could not have intent(out) or inout attribute or implicit inout as this would be in error.

Jim Dempsey

0 Kudos
Reply