Paul
Paul

Reputation: 4430

Memory leak with derived type pointer

When I run the code below through either gfortran and Valgrind or ifort and Intel Inspector a memory leak is detected the first time the procedure set is called for a object. The second time does not seem to cause any memory leaks though. Why is that?

module mymod
    implicit none

    type mytype
        integer, pointer :: intArray(:) => null()
    contains
        procedure :: set
    end type mytype

contains

    subroutine set(this, intArray)
        class(mytype), intent(inout) :: this
        integer, intent(in) :: intArray(:)
        integer n

        n = size(intArray)

        nullify(this%intArray)
        allocate(this%intArray(n)) !line 20
        this%intArray = intArray

    end subroutine set

end module mymod

program main
    use mymod !line 28
    implicit none

    type(mytype) :: myvar

    call myvar%set((/1,2,3/)) !line 33
    print *, myvar%intArray
    call myvar%set((/9,8,7,6,5/))
    print *, myvar%intArray

end program main

Valgrind reports the following memory leak:

==6669== 12 bytes in 1 blocks are definitely lost in loss record 1 of 2
==6669==    at 0x402BB7A: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==6669==    by 0x804886A: __mymod_MOD_set (main.f90:20)
==6669==    by 0x8048988: MAIN__ (main.f90:33)
==6669==    by 0x8048ADC: main (main.f90:28)

For line numbers, see the comments in the code.

Upvotes: 0

Views: 670

Answers (2)

The leak actually happens on the second call of set. You nullify the pointer, but it is already associated and the content is lost. So, you must call deallocate before and test the association status with associated().

Upvotes: 2

IanH
IanH

Reputation: 21431

The first time the set binding is called you allocate an "anonymous" size three array to store the supplied integers. At the same time you associate the intArray component to point at that newly allocated array - when you ALLOCATE pointers the statement is conceptually doing two things.

The second time the set binding is called you break the association between the intArray component and the allocation with the NULLIFY statement, before you repeat the pointer allocation process.

Nullify does not (necessarily) deallocate. Your program has basically lost track of that initial allocation of a size three array. Three integers, typically four bytes per integer -- twelve bytes lost.

If you are using pointers, a general principle is that for every ALLOCATE encountered in your code path you need to have a matching DEALLOCATE in the later code path.

(In Fortran 2003 or later (which is what you are using, because you have type bound procedures), you should only be using pointers and pointer components if you are actually pointing them at things. If you are really just using the pointers as "values", then you should be using allocatable variables or components.)

Upvotes: 4

Related Questions