Community
cancel
Showing results for 
Search instead for 
Did you mean: 
pwl_b
Beginner
395 Views

A pointer passed to DEALLOCATE points to an object that cannot be deallocated

Compiling (with ifort 13.1.1) and executing the following code

[fortran]

module tt

  type :: t
  end type t

  type :: t1
     class(t), pointer :: tp
   contains
     procedure :: set
     procedure :: unset
  end type t1

contains

  function t_new() result(r)
    type(t), pointer :: r
    allocate(r)
  end function t_new

  subroutine set(a, tp)
    class(t1) :: a
    class(t), target :: tp
    a%tp => tp
  end subroutine set

  subroutine unset(a)
    class(t1) :: a
    print *, "Dealocating"
    deallocate(a%tp)
    print *, "Deallocated"
  end subroutine unset

end module tt


program test

  use tt

  type(t1) :: a

  call a%set(t_new())
  call a%unset()

end program test

[/fortran]

I get

[plain]

 Dealocating
forrtl: severe (173): A pointer passed to DEALLOCATE points to an object that cannot be deallocated
Image              PC                Routine            Line        Source             
pointer            000000000046D7AE  Unknown               Unknown  Unknown
pointer            000000000046C246  Unknown               Unknown  Unknown
pointer            0000000000424FC2  Unknown               Unknown  Unknown
pointer            00000000004068BB  Unknown               Unknown  Unknown
pointer            00000000004050E6  Unknown               Unknown  Unknown
pointer            0000000000402C57  Unknown               Unknown  Unknown
pointer            0000000000402B3C  Unknown               Unknown  Unknown
libc.so.6          00007FB324690A15  Unknown               Unknown  Unknown
pointer            0000000000402A39  Unknown               Unknown  Unknown

[/plain]

but using gfortran yields

[plain]

 Dealocating
 Deallocated

[/plain]

Is this a bug?

Best,

Paweł Biernat

0 Kudos
20 Replies
Steven_L_Intel1
Employee
378 Views

Yes, it is a bug. I have escalated it as issue DPD200243572. A workaround is to have t_new return a class(t) pointer that is allocated as type(t), for example:

[fortran]
  function t_new() result(r)
   class(t), pointer :: r
    allocate(t::r)
  end function t_new
[/fortran]

pwl_b
Beginner
378 Views

Thanks, I will use the workaround.

Paweł

jimdempseyatthecove
Black Belt
378 Views

Steve,

Why is scoping required on the allocate?

Jim Dempsey

Steven_L_Intel1
Employee
378 Views

Jim, if you mean the t::, that specifies the dynamic type of the allocated polymorphic object. It is not strictly necessary in this case, as without it the declared type t is used anyway, but I like to put it in there for clarity when allocating a polymorphic object.

Steven_L_Intel1
Employee
378 Views

An alternative workaround, and one I think is "more correct", is to make the tp argument to set a pointer rather than target. The problem is that anything could be a target and not necessarily something that was allocated. We need to look at this closer and it may be a while before we have an answer. But regardless, I think pointer is the right thing to use in set.

IanH
Black Belt
378 Views

In F2003 (specifically), can the value that results from the evaluation of an expression have the target attribute?

Steven_L_Intel1
Employee
378 Views

No - "An entity with the TARGET attribute shall be a variable" (C555 in F2008) I discussed this with the developers and their position is that the current behavior is correct - doing a pointer assignment to something that isn't a pointer loses the ability to deallocate it later through that pointer, even if that thing was itself allocated. I am going to be out the next three weeks and will have to defer study of what the standard says about this until I get back.
pwl_b
Beginner
378 Views

So is the statement

[fortran]

call a%set(t_new())

[/fortran]

valid in F2008 at all? Should I avoid using the result of a function as an argument this way and introduce temporary variable instead?

[fortran]

class(t), pointer :: tmp

tmp=>t_new()

call a%set(tmp)

[/fortran]

Paweł

IanH
Black Belt
378 Views

That specific statement is valid F2003/F2008, the problem is what happens afterwards, particularly when the set procedure finishes.  I think in F2003 the pointer association status of the tp component becomes undefined - this is because the dummy argument that it is pointed at is associated with an actual argument that is an expression, as part of the call that expression is evaluated, evaluation of an expression produces a value, as Steve says - a value cannot be a target, when you have a non-target actual associated with a target dummy the pointer association status of things pointed at the dummy becomes undefined when the procedure terminates.

In F2008 a variable can be a function reference that has a data pointer result (which I don't think ifort does yet, but I think gfortran does).  A variable can be a target - whatever the function result points at has to have had the target attribute.  So you have a target actual with a target dummy.  So things are ...umm... different.  After that - I get confused and give up.  Part of my confusion resulted in a post to c.l.f.

Edit to note that the first paragraph above is all wrong.  See interp F95/0074 case 3.

S_2
Beginner
378 Views

Dear all,

Does anyone working at intel know the status of this issue? is there a plan to fix it?
I run into the same issue with the last version of the intel compiler (2019). Even though the workaround of using a class(t) pointer that is allocated as type(t) works, it makes some code harder to read and to write since a "select type" is needed when working on the pointer.

EDIT: my bad, I didn't understand the workaround properly, select type is indeed not needed.

Lu__You
Beginner
173 Views

Hi Steven,

I am wondering how this type of function, what returns a pointer as result that is allocated locally, can avoid memory leak by proper deallocating. I have an application of such pattern in a recursive function. Many thanks.

You

Steve_Lionel
Black Belt Retired Employee
158 Views

@Lu__You , this is entirely the programmer's responsibility. Fortran doesn't give you any help here. 

Lu__You
Beginner
154 Views

@Steve_Lionel

Thank you. Surely it is. But is it even possible in theory to deallocate such result pointers in Fortran? I would appreciate it if you have any suggestions.

Steve_Lionel
Black Belt Retired Employee
146 Views

Of course. Assuming you use pointer assignment and not intrinsic assignment:

 

program test
    implicit none
    integer, pointer :: p => null()
    
    p => f(3)
    print *, associated(p), p
    deallocate (p)
    print *, associated(p)
    
    contains
    
    function f(x)
    integer, pointer :: f
    integer, intent(in) :: x
    allocate (f)
    f = x
    return
    end function f
    
    end program test
    

 

 T           3
 F
Lu__You
Beginner
137 Views

@Steve_Lionel 

Thank you for the quick response.

Sorry I forgot to make it clear that I was just using the intrinsic allocate function, something like:

recursive function returnScalar(meta) result(val)

class(*), pointer :: val

allocate(val, source=returnScalar(meta%next))

...

But it's also very helpful to confirm that such implementation can't avoid a leak. Thank you very much.

Steve_Lionel
Black Belt Retired Employee
125 Views

Yes, it CAN leak. It's up to you to make sure it doesn't. 

Your question is not really related to this thread, however.

Lu__You
Beginner
118 Views

Apologies for digressing! But thanks a lot for the discussion!

FortranFan
Honored Contributor I
92 Views

@Steve_Lionel wrote:
.. Your question is not really related to this thread, however.

@Yu__Lou wrote:
Apologies for digressing! But thanks a lot for the discussion!

 

@Lu__You ,

You're on the right track in thinking about memory leak issues in codes that do allocations in recursive functions the way you show in a brief snippet.

As implied by @Steve_Lionel comment, your concerns are worth for a different thread.

And indeed such a thread can involve code design aspects as well as modern Fortran language facilities.

A good place for such a discussion will be the Fortran Discourse site at:

https://fortran-lang.discourse.group/

I suggest you open up a thread at this Discourse site and share as much details regarding the code you have in mind with recursive functions, unlimited polymorphic object with POINTER attribute, and possible a linked list like derived type.

Lu__You
Beginner
76 Views

@FortranFan 

Thank you for the suggestion. It's indeed a good idea to have some discussions there!--It's more about intrinsic limits of the current Fortran language standards.

In fact I am following the current thread because I'm having a similar difficulty of deallocating pointers to unlimited polymorphic components of a derived type. (It's another concern of memory leak!) It segfaults as of 17.0.2. Then I happened to see @Steve_Lionel's snippet code of returning a pointer in a similar concept of my memory-leaking implementation. Lol