Compiling (with ifort 13.1.1) and executing the following code
type :: t
end type t
type :: t1
class(t), pointer :: tp
procedure :: set
procedure :: unset
end type t1
function t_new() result(r)
type(t), pointer :: r
end function t_new
subroutine set(a, tp)
class(t1) :: a
class(t), target :: tp
a%tp => tp
end subroutine set
class(t1) :: a
print *, "Dealocating"
print *, "Deallocated"
end subroutine unset
end module tt
type(t1) :: a
end program test
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
but using gfortran yields
Is this a bug?
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:
function t_new() result(r)
class(t), pointer :: r
end function t_new
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.
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
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
But it's also very helpful to confirm that such implementation can't avoid a leak. Thank you very much.
@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!
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:
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.
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
OOPS, I wrote the following before seeing the above post.
Ignore the following (as you are using TBP)
>> I'm having a similar difficulty of deallocating pointers to unlimited polymorphic components of a derived type.
The above states that you have an external (to the derived type) pointer to an allocatable within the derived type.
Should this component be ALLOCATABLE, it would also have to have the TARGET attribute .AND. the (external) pointer could not deallocate this component.
Should this component be POINTER (which is/was allocated), then the external pointer could perform the deallocate **** with your requirement to NULLIFY the component pointer, and all other pointers that may be pointing to that component.
You would be best served by creating a type bound function/subroutine to perform this.
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.
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.
So is the statement
valid in F2008 at all? Should I avoid using the result of a function as an argument this way and introduce temporary variable instead?
class(t), pointer :: tmp
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.
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.