I will commit the attached patch approved by Paul on MatterMost. This fixes a
memory leak found in the PDT_70 test case.
Regression tested on x86_64
Thanks for review Paul.
Regards,
Jerry
---
fortran: Fix finalizer list truncated when >= 3
finalizers match [PR121972]
When gfc_resolve_finalizers copies matching finalizers from the template
type into a derived type's finalizer list, a linked-list bug caused the
third and later entries to be orphaned. Fix by using the standard
tail-pointer idiom.
PR fortran/121972
gcc/fortran/ChangeLog:
* resolve.cc (gfc_resolve_finalizers): Fix linked-list tail-pointer
bug that dropped all but the first two finalizers from a derived
type's finalizer list when three or more matched.
gcc/testsuite/ChangeLog:
* gfortran.dg/pdt_70.f03: Add a matrix finalizer and update the
check of the value of 'flag'.
---From cff889aa9f1ffcfce367bbed29fd9004b2567b93 Mon Sep 17 00:00:00 2001
From: Jerry DeLisle <[email protected]>
Date: Mon, 29 Jun 2026 08:36:06 -0700
Subject: [PATCH] fortran: Fix finalizer list truncated when >= 3
finalizers match [PR121972]
When gfc_resolve_finalizers copies matching finalizers from the template
type into a derived type's finalizer list, a linked-list bug caused the
third and later entries to be orphaned. Fix by using the standard
tail-pointer idiom.
PR fortran/121972
gcc/fortran/ChangeLog:
* resolve.cc (gfc_resolve_finalizers): Fix linked-list tail-pointer
bug that dropped all but the first two finalizers from a derived
type's finalizer list when three or more matched.
gcc/testsuite/ChangeLog:
* gfortran.dg/pdt_70.f03: Add a matrix finalizer and update the
check of the value of 'flag'.
---
gcc/fortran/resolve.cc | 9 ++-------
gcc/testsuite/gfortran.dg/pdt_70.f03 | 27 ++++++++++++++++++++++-----
2 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index d479b6a80e5..9a820c179f5 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -16402,13 +16402,8 @@ gfc_resolve_finalizers (gfc_symbol* derived, bool *finalizable)
tmp = gfc_get_finalizer ();
*tmp = *list;
tmp->next = NULL;
- if (*prev_link)
- {
- (*prev_link)->next = tmp;
- prev_link = &tmp;
- }
- else
- *prev_link = tmp;
+ *prev_link = tmp;
+ prev_link = &(tmp->next);
list->proc_tree = gfc_find_sym_in_symtree (list->proc_sym);
}
}
diff --git a/gcc/testsuite/gfortran.dg/pdt_70.f03 b/gcc/testsuite/gfortran.dg/pdt_70.f03
index 25801ed9549..0709dfbc7b3 100644
--- a/gcc/testsuite/gfortran.dg/pdt_70.f03
+++ b/gcc/testsuite/gfortran.dg/pdt_70.f03
@@ -3,6 +3,12 @@
! PR104650
! Contributed by Gerhard Steinmetz <[email protected]>
!
+! Sometime later, after the original fix, it was noted that this test
+! leaked memory. This was originally because subroutine finalize_t1m
+! was unavailable. Adding it, resulted in the first in the FINAL list
+! not being called. This has been retained and a dimension-3 variable
+! 'e' added.
+!
module m1
type t1
integer :: i
@@ -30,7 +36,7 @@ module m2
integer, kind :: k
real(k), pointer :: vector(:) => NULL ()
contains
- final :: finalize_t1s, finalize_t1v, finalize_t2e
+ final :: finalize_t1s, finalize_t1v, finalize_t1m, finalize_t2e
end type
integer :: flag = 0
@@ -51,6 +57,16 @@ contains
end do
end subroutine
+ impure subroutine finalize_t1m(x)
+ type(t(kind(0.0))) x(:,:)
+ do i = lbound(x,1), ubound(x,1)
+ do j = lbound(x,2), ubound(x,2)
+ if (associated(x(i,j)%vector)) deallocate(x(i,j)%vector)
+ flag = flag + 1
+ end do
+ end do
+ end subroutine
+
impure elemental subroutine finalize_t2e(x)
type(t(kind(0.0d0))), intent(inout) :: x
if (associated(x%vector)) deallocate(x%vector)
@@ -80,7 +96,7 @@ end module
! Test the standard example
call example (dims)
- if (flag /= 11 + dims**2) stop 2
+ if (flag /= 11 + 2 * dims**2) stop 2
contains
@@ -94,19 +110,20 @@ contains
! Returning from 'example' will effectively do
! call finalize_t1s(a)
! call finalize_t1v(b)
+! call finalize_t1m(c)
! call finalize_t2e(d)
-! No final subroutine will be called for variable C because the user
+! No final subroutine will be called for variable e because the user
! omitted to define a suitable specific procedure for it.
subroutine example(n)
- type(t(kind(0.0))) a, b(10), c(n,2)
+ type(t(kind(0.0))) a, b(10), c(n,2), e(2,2,2)
type(t(kind(0.0d0))) d(n,n)
- real(kind(0.0)),target :: tgt(1)
! Explicit allocation to provide a valid memory refence for deallocation.
call alloc_ts(a)
call alloc_ts(b)
call alloc_ts(c)
call alloc_td(d)
+ call alloc_ts(e)
end subroutine
end
--
2.54.0