Finalization of allocatable function result

Finalization of allocatable function result

Consider the following code

MODULE mod
  TYPE typ
     INTEGER   :: i = 1
   CONTAINS
     PROCEDURE :: mul
     FINAL     :: destruct
  END TYPE typ
CONTAINS
  FUNCTION mul(a,m) RESULT (b)
    CLASS (typ), INTENT (in) :: a
    INTEGER,     INTENT (in) :: m
    CLASS (typ), ALLOCATABLE :: b

    ALLOCATE(b, source=a)
    b%i = b%i * m
  END FUNCTION mul

  SUBROUTINE destruct(a)
    TYPE (typ), INTENT (inout) :: a
    PRINT *, 'destructor called'
  END SUBROUTINE destruct
END MODULE mod

PROGRAM test
  USE mod
  TYPE(typ) :: a, b

  b = a
  PRINT *
  b = mul(a,5)
  PRINT *, b%i
END PROGRAM test

When compiled with ifort (version 12.1.1.256), both assignments in the main program call the final subroutine once (for the left hand side variable). I would expect that the second assignment should call it twice; the extra finalization should be for the allocated function result of 'mul'. Is it a bug in ifort or am I wrong?

14 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

You are, um, mistaken, though this is a very tricky part of the standard to understand.

Your final subroutine gets called twice for b, following this rule:

"When an intrinsic assignment statement is executed, the variable is finalized after the evaluation of expr and before the definition of the variable." [Fortran 2008,4.5.6.3, paragraph 9]

For the function call, two rules apply:

"If an executable construct references a function, the result is finalized after execution of the innermost executable construct containing the reference." [paragraph 4]

so in this case, the function result would get finalized at the end of the program. But...

"If image execution is terminated, either by an error (e.g. an allocation failure) or by execution of a stop-stmt, error-stop-stmt, or end-program-stmt, entities existing immediately prior to termination are not finalized." [4.5.6.4]

Since in this case, the function result still exists at the END PROGRAM, it does not get finalized.

Steve - Intel Developer Support

Thank you very much for answering.

I suppose that there is no way to force the finalization of the allocated function result at a specific point in the code. It is inaccessible after the assignment. Doesn't this lead to a memory leak?

By the way, IBM xlf v13.1 calls the final subroutine twice for the second assignment, right after the completion of the assignment, avoiding the leak.

There was some debate in the standards process about when such finalizations should occur. There is no memory leak since all allocated memory is effectively deallocated when the program exits. Even within the program, the "mul" function deallocates its function result on entry automatically. Can you demonstrate a program with a leak?

I would think that xlf's behavior is not conforming to the standard, but it might be difficult to write a conforming program that could really tell.

Steve - Intel Developer Support

My point is that the "mul" function should, but does not, deallocate its result automatically, the final routine is not called. Consider this

MODULE modu
  TYPE typ
     REAL, ALLOCATABLE :: r(:)
   CONTAINS
     PROCEDURE :: copy
     FINAL     :: destruct
  END TYPE typ
CONTAINS
  FUNCTION copy(a) RESULT (b)
    CLASS (typ), INTENT (in) :: a
    CLASS (typ), ALLOCATABLE :: b

    ALLOCATE(b, source = a)
  END FUNCTION copy

  SUBROUTINE destruct(a)
    TYPE (typ), INTENT (inout) :: a
  END SUBROUTINE destruct
END MODULE modu

PROGRAM test
  USE modu
  TYPE(typ) :: a, b

  ALLOCATE(a%r(2))

  DO  
     b = a%copy()
  END DO

END PROGRAM test

When compiled with ifort, the executable has a memory leak. Isn't the code standard conforming?

There is no memory leak. Why do you think there is? I modified the program to demonstrate this.

MODULE modu
  TYPE typ
     REAL, ALLOCATABLE :: r(:)
   CONTAINS
     PROCEDURE :: copy
     FINAL     :: destruct
  END TYPE typ
CONTAINS
  FUNCTION copy(a) RESULT (b)
    CLASS (typ), INTENT (in) :: a
    CLASS (typ), ALLOCATABLE :: b

    ALLOCATE(b, source = a)
    PRINT *, "In copy, LOC(b)=",LOC(b)
  END FUNCTION copy

  SUBROUTINE destruct(a)
    TYPE (typ), INTENT (inout) :: a
  END SUBROUTINE destruct
END MODULE modu

PROGRAM test
  USE modu
  TYPE(typ) :: a, b

  ALLOCATE(a%r(2))

  DO  I=1,10
     b = a%copy()
  END DO

END PROGRAM test

I was at the standards committee meeting where this topic was discussed. IBM had already implemented its approach but the vote was overwhelmingly in favor of the way the standard worded it.

Steve - Intel Developer Support

There is a memory leak; Intel inspector XE finds it and /usr/bin/top during execution shows my computer's memory being eaten away.

You might not be observing a memory leak. What you might be observing is a "feature". Some of the heap managers are now of GC (garbage collector) design. Meaning, returned nodes are not immediately recycled. Instead they are "quarantined" before recycled. The reason for doing this is two-fold: a) reduces the number of heap locks on returning nodes, and b) in the event of bad programming design (bug) where buffer is used after delete and this practice can/might hide the error.

To find out if leak:

if you can set upper limit on heap do so and run the program and see if it crashes after sufficient allocations to expend the upper limit on heap.

If you cannot set upper limit on heap you usually can specify upper limit on page file. Run the program andtrack page file usage. When page file maxes out, if your program continues to run, then there is no memory leak.

Jim Dempsey

www.quickthreadprogramming.com

I know there is a memory leak; the first time it almost crashed my computer. Anyway, I have tried what you suggest: I have set a relatively small upper limit to virtual memory and the program crashed when it reached it. The error message was:
Insufficient memory to allocate Fortran RTL message buffer, message #41 = hex 00000029

Intel Inspector finds the memory leak. Therefore, there is a bug either in the compiler or the memory checker!

No, there is a memory leak - I see it now. But it might be a compiler bug relating to the deallocation of INTENT(OUT) derived types. The finalization is being done the way the standard says it should.

I will look at this more closely.

Steve - Intel Developer Support

I simplified the program a lot, removing CLASS, type-bound procedures and finalizers. The fundamental issue is that an allocatable function result that contains allocatable components does not have those subcomponents deallocated when the function value is consumed. I have escalated this as issue DPD200176255.

Steve - Intel Developer Support

The memory leak issue will be fixed in a release later this year.

Steve - Intel Developer Support

Have this bug corrected in V2013?

Yes, the bug reported here should be fixed in the 2013 version.

Steve - Intel Developer Support

Leave a Comment

Please sign in to add a comment. Not a member? Join today