https://gcc.gnu.org/g:1a2de01fbac64f97fed6f63ff655b13bff831877

commit r17-2028-g1a2de01fbac64f97fed6f63ff655b13bff831877
Author: Paul Thomas <[email protected]>
Date:   Tue Jun 30 10:39:57 2026 +0100

    Fortran: Fix memory leak found in pdt_86.f03 [PR121972]
    
    Followup on memory leaks found using -fsanitize=address
    in existing test cases.
    
    Co-authored-by: Jerry DeLisle <[email protected]>
    
            PR fortran/121972
    
    gcc/fortran/
    
            * decl.cc (gfc_get_pdt_instance): A PDT that has a derived type
            component, which has allocatable components, must be marked as
            having allocatable components.
            * resolve.cc (gfc_resolve_ref): Initialize last_pdt from the base
            symbol's declared type when the expression type is not a PDT.
    
    gcc/testsuite/
    
            * gfortran.dg/pdt_86.f03: Add tree dump for counts of frees and
            mallocs (41 & 31 respectively).
            * gfortran.dg/pdt_86_reduced.f90: New test to check that the
            non-PDT version of the leak has gone.

Diff:
---
 gcc/fortran/decl.cc                          |  4 +++-
 gcc/fortran/resolve.cc                       |  7 ++++++-
 gcc/testsuite/gfortran.dg/pdt_86.f03         |  3 +++
 gcc/testsuite/gfortran.dg/pdt_86_reduced.f90 | 26 ++++++++++++++++++++++++++
 4 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/gcc/fortran/decl.cc b/gcc/fortran/decl.cc
index 63941edebd9a..6dad9d9791a4 100644
--- a/gcc/fortran/decl.cc
+++ b/gcc/fortran/decl.cc
@@ -4626,7 +4626,9 @@ gfc_get_pdt_instance (gfc_actual_arglist *param_list, 
gfc_symbol **sym,
                }
            }
 
-         if (c2->attr.allocatable)
+         if (c2->attr.allocatable
+             || (c2->ts.type == BT_DERIVED && c2->ts.u.derived
+                 && c2->ts.u.derived->attr.alloc_comp && !c2->attr.pointer))
            instance->attr.alloc_comp = 1;
        }
       else if (!(c2->attr.pdt_kind || c2->attr.pdt_len || c2->attr.pdt_string
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 12502f950b3e..9eb022d608d8 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -6164,7 +6164,12 @@ gfc_resolve_ref (gfc_expr *expr)
   n_components = 0;
   array_ref = NULL;
 
-  if (expr->expr_type == EXPR_VARIABLE && IS_PDT (expr))
+  /* Use the declared type of the base symbol to initialize last_pdt when the
+     expression is not itself a PDT. This matters for ASSOCIATE variables whose
+     component reference may still point to a PDT template.  */
+  if (expr->expr_type == EXPR_VARIABLE
+      && (IS_PDT (expr)
+         || (expr->ref && expr->symtree && IS_PDT (expr->symtree->n.sym))))
     last_pdt = expr->symtree->n.sym->ts.u.derived;
 
   for (ref = expr->ref; ref; ref = ref->next)
diff --git a/gcc/testsuite/gfortran.dg/pdt_86.f03 
b/gcc/testsuite/gfortran.dg/pdt_86.f03
index 6e7798ecfbae..fe7057cd1dda 100644
--- a/gcc/testsuite/gfortran.dg/pdt_86.f03
+++ b/gcc/testsuite/gfortran.dg/pdt_86.f03
@@ -1,4 +1,5 @@
 ! { dg-do run }
+! { dg-options "-fdump-tree-original" }
 !
 ! Test the fix for PR122902. Line 47 gave "free(): invalid pointer".
 !
@@ -55,3 +56,5 @@ end submodule
   if (allocated(input_output_pairs)) deallocate(input_output_pairs)
   if (allocated(mini_batch)) deallocate(mini_batch)
 end
+! { dg-final { scan-tree-dump-times "__builtin_malloc" 31 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_free" 41 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/pdt_86_reduced.f90 
b/gcc/testsuite/gfortran.dg/pdt_86_reduced.f90
new file mode 100644
index 000000000000..608a1bbb14c4
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pdt_86_reduced.f90
@@ -0,0 +1,26 @@
+! { dg-do compile }
+! { dg-options "-fdump-tree-original" }
+!
+! Check the fix for the memory leak in pdt_77.f03. This test is a reduced
+! version of the original that isolates the source of the leak. Note that
+! the leak is not PDT specific.
+!
+module input_output_pair_m
+  implicit none
+  type tensor_t                             ! No longer a PDT!
+    real(kind(1e0)), allocatable :: values_(:)
+  end type
+end module
+
+  use input_output_pair_m
+  call test
+contains
+  subroutine test
+    implicit none
+    type(tensor_t), allocatable :: inputs(:)
+    integer :: i
+    inputs = [(tensor_t([real(i)]), i=1,2)] ! Leaked 8 bytes in 2 blocks.
+  end
+end
+! { dg-final { scan-tree-dump-times "__builtin_malloc" 7 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_free" 8 "original" } }

Reply via email to