aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorAndre Vehreschild <vehre@gcc.gnu.org>2023-07-12 16:52:15 +0200
committerAndre Vehreschild <vehre@gcc.gnu.org>2024-05-29 10:25:44 +0200
commit2f97d98d174e3ef9f3a9a83c179d787abde5e066 (patch)
tree939fd3f120ba0cd464bde0b97152f2ec70deedd1 /gcc
parenta99ebb88f8f25e76ebed5afc22e64fa77a2f0d3f (diff)
downloadgcc-2f97d98d174e3ef9f3a9a83c179d787abde5e066.zip
gcc-2f97d98d174e3ef9f3a9a83c179d787abde5e066.tar.gz
gcc-2f97d98d174e3ef9f3a9a83c179d787abde5e066.tar.bz2
Fix memory leak.
Prevent double call of function return class object and free the object after copy. gcc/fortran/ChangeLog: PR fortran/90069 * trans-expr.cc (gfc_conv_procedure_call): Evaluate expressions with side-effects only ones and ensure old is freeed. gcc/testsuite/ChangeLog: PR fortran/90069 * gfortran.dg/class_76.f90: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/fortran/trans-expr.cc29
-rw-r--r--gcc/testsuite/gfortran.dg/class_76.f9066
2 files changed, 92 insertions, 3 deletions
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index dfc5b8e..9f6cc8f 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -6725,9 +6725,32 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
{
tree efield;
- /* Evaluate arguments just once. */
- if (e->expr_type != EXPR_VARIABLE)
- parmse.expr = save_expr (parmse.expr);
+ /* Evaluate arguments just once, when they have
+ side effects. */
+ if (TREE_SIDE_EFFECTS (parmse.expr))
+ {
+ tree cldata, zero;
+
+ parmse.expr = gfc_evaluate_now (parmse.expr,
+ &parmse.pre);
+
+ /* Prevent memory leak, when old component
+ was allocated already. */
+ cldata = gfc_class_data_get (parmse.expr);
+ zero = build_int_cst (TREE_TYPE (cldata),
+ 0);
+ tmp = fold_build2_loc (input_location, NE_EXPR,
+ logical_type_node,
+ cldata, zero);
+ tmp = build3_v (COND_EXPR, tmp,
+ gfc_call_free (cldata),
+ build_empty_stmt (
+ input_location));
+ gfc_add_expr_to_block (&parmse.finalblock,
+ tmp);
+ gfc_add_modify (&parmse.finalblock,
+ cldata, zero);
+ }
/* Set the _data field. */
tmp = gfc_class_data_get (var);
diff --git a/gcc/testsuite/gfortran.dg/class_76.f90 b/gcc/testsuite/gfortran.dg/class_76.f90
new file mode 100644
index 0000000..1ee1e1f
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/class_76.f90
@@ -0,0 +1,66 @@
+! { dg-do compile }
+! { dg-additional-options "-fdump-tree-original" }
+!
+! PR fortran/90069
+!
+! Contributed by Brad Richardson <everythingfunctional@protonmail.com>
+!
+
+program returned_memory_leak
+ implicit none
+
+ type, abstract :: base
+ end type base
+
+ type, extends(base) :: extended
+ end type extended
+
+ type :: container
+ class(*), allocatable :: thing
+ end type
+
+ call run()
+contains
+ subroutine run()
+ type(container) :: a_container
+
+ a_container = theRightWay()
+ a_container = theWrongWay()
+ end subroutine
+
+ function theRightWay()
+ type(container) :: theRightWay
+
+ class(base), allocatable :: thing
+
+ allocate(thing, source = newAbstract())
+ theRightWay = newContainer(thing)
+ end function theRightWay
+
+ function theWrongWay()
+ type(container) :: theWrongWay
+
+ theWrongWay = newContainer(newAbstract())
+ end function theWrongWay
+
+ function newAbstract()
+ class(base), allocatable :: newAbstract
+
+ allocate(newAbstract, source = newExtended())
+ end function newAbstract
+
+ function newExtended()
+ type(extended) :: newExtended
+ end function newExtended
+
+ function newContainer(thing)
+ class(*), intent(in) :: thing
+ type(container) :: newContainer
+
+ allocate(newContainer%thing, source = thing)
+ end function newContainer
+end program returned_memory_leak
+
+! { dg-final { scan-tree-dump-times "newabstract" 14 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_free" 8 "original" } }
+