Hi all,

attached patch fixes a 15-regression where an element of an actual
temporary array, i.e., elemental([ e1, e2...]) passed to the formal polymorphic
dummy leads to a double free of the derived types components. This patch
prevents this by preventing the deallocation of the array constructors
temporary, when the formal is polymorphic. ...

Folks its so hard to explain this in prose. I rewrote above paragraph the third
time now. And I still don't understand on re-reading. So here is some pseudo
code:

struct derived {
  char *c; // This is the component suffering from double-free
};

derived[2] atmp = [ derived(""), derived("")]

forall a in atmp
  derived t_a = a; // <- Copy of a, but no deep copy, i.e. t_a.c == a.c
  class_temp = class_derived(a); // set _vtype left out for brevity
  call elemental_function(class_temp);
  if (class_temp._data.c != NULL)
    free(class_temp._data.c); // and set it to NULL
  if (t_a.c != NULL)
    free(t_a.c); // BOOM, this is freeing the same c
end

Generating the last if-block and the free is what this patch prevents for
polymorphic dummys that stem from an array construction. And only for those.

Sorry, I am having a hard time explaining things today. So I hope the code
above will do.

Regtested ok on x86_64-pc-linux-gnu / F41. Ok for mainline?

Regards,
        Andre
--
Andre Vehreschild * Email: vehre ad gmx dot de
From 8f9c24fe01a1e34bea2e1c95102329562abdb9e1 Mon Sep 17 00:00:00 2001
From: Andre Vehreschild <ve...@gcc.gnu.org>
Date: Thu, 20 Mar 2025 13:37:21 +0100
Subject: [PATCH] Fortran: Fix double free on polymorphic array dummy argument
 [PR119349]

Calling elemental routines with polymorphic formals leads to generation
of a temporary polymorphic variable and code for its deallocation.
Sourcing this element from an array constructor the latter now is
prevented from generating a second deallocation.

	PR fortran/119349

gcc/fortran/ChangeLog:

	* trans-expr.cc (gfc_conv_procedure_call): Prevent deallocation
	of array temporary for polymorphic temporary argument.

gcc/testsuite/ChangeLog:

	* gfortran.dg/class_79.f90: New test.
---
 gcc/fortran/trans-expr.cc              |  6 +++++-
 gcc/testsuite/gfortran.dg/class_79.f90 | 25 +++++++++++++++++++++++++
 2 files changed, 30 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gfortran.dg/class_79.f90

diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index d965539f11e..923d46cb47c 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -7994,7 +7994,11 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 	      gfc_add_expr_to_block (&se->post, local_tmp);
 	    }

-	  if (!finalized && !e->must_finalize)
+	  /* Items of array expressions passed to a polymorphic formal arguments
+	     create their own clean up, so prevent double free.  */
+	  if (!finalized && !e->must_finalize
+	      && !(e->expr_type == EXPR_ARRAY && fsym
+		   && fsym->ts.type == BT_CLASS))
 	    {
 	      bool scalar_res_outside_loop;
 	      scalar_res_outside_loop = e->expr_type == EXPR_FUNCTION
diff --git a/gcc/testsuite/gfortran.dg/class_79.f90 b/gcc/testsuite/gfortran.dg/class_79.f90
new file mode 100644
index 00000000000..a2226e47aff
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/class_79.f90
@@ -0,0 +1,25 @@
+!{ dg-do run }
+
+! Check double free on array constructor in argument list is fixed.
+! Contributed by Damian Rouson  <damian@archaeologic.codes>
+program pr119349
+  implicit none
+
+  type string_t
+    character(len=:), allocatable :: string_
+  end type
+
+  print *, true([string()])
+
+contains
+
+  type(string_t) function string()
+    string%string_ = ""
+  end function
+
+  logical elemental function true(rhs)
+    class(string_t), intent(in) :: rhs
+    true = .true.
+  end function
+
+end program
--
2.48.1

Reply via email to