Dear all,
I faced with a possible serious bug: polymorphic functions (necessary
to define polymorphic operators in OOP programs) generate memory leaks
making OOP program not feasible.

I opened a bug report (80477) here
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80477

I report the details also below.

My best regards.

Issue summary

In the attached example "polymorphic_operators_memory_leaks.f90" I
show the possible bug in less than 100 lines. Essentially, the derived
type "a_type_t" defines the operators "=" and "+" in a polymorphic way
(in order to allow "a_type_t" to be extended while all other "agents"
using "a_type_t" do not need to be changed, OOP). The assignment
operator does not create memory leaks because it is subroutine that
does not allocate temporary. On the contrary, the operator "+" is a
function that allocates a temporary: this temporary generates the
memory leaks because it is not correctly destroyed after its usage.

I checked the above conclusion with "valgrind" and it confirms that
the "+" operator (function) generates the leaks. Note that the same
code compiled and run with Intel Fortran (17.0.2) does not generates
memory leaks and it works as expected. Moreover, is the "+"
operator/function is modified disallowing polymorphic (namely changing
"class(a_type_t), allocatable :: res" with "type(a_type_t) :: res" the
leaks disappear, thus I could conclude that the leaks are generated
only for polymorphic function results.

A word of advice: the test is designed to point out the memory leaks
occurrences, running it your RAM will be quickly consumed! Please, be
rapid to quickly kill it before your OS start swapping on HD. To test
it with valgrind I added a little "ui": it can be executed without
arguments, thus its loop will be very long (and your RAM totally
consumed) or you can pass one integer argument and the loop will do
the iterations you provided, e.g. "a.out 1" will execute 1 iteration
loop. This is written into the code comments.

Please, consider that if this is really a bug, all serious OOP
programs are indeed impossible to be done.

Thank you very much for your help.

Stefano Zaghi  Ph.D. Aerospace Engineer

Research Scientist, Dept. of Computational Hydrodynamics at CNR-INSEAN
p: +39 0650299260 | m: +39 3497730036 | e: stefano.za...@gmail.com

Member of Fortran-FOSS-Programmers

Codes Showcase
OFF          Open source Finite volumes Fluid dynamics code
Lib_VTK_IO   Fortran library to write and read data conforming the VTK standard
FLAP         Fortran command Line Arguments Parser for poor men
BeFoR64      Base64 encoding/decoding library for FoRtran poor men
FiNeR        Fortran INI ParseR and generator for FoRtran poor men
IR_Precision Fortran (standard 2003) module to develop portable codes
FoBis.py     Fortran Building System for poor men
PreForM.py   Preprocessor for Fortran poor men
MaTiSSe.py   Markdown To Impressive Scientific Slides
module a_type_m

   implicit none

   integer, parameter :: LENGTH = 100

   type :: a_type_t
      real :: x(LENGTH)
   contains
      ! operators
      generic :: assignment(=) => assign_a_type
      generic :: operator(+) => add_a_type
      procedure, pass(lhs) :: assign_a_type
      procedure, pass(lhs) :: add_a_type
   endtype a_type_t

contains
   subroutine assign_a_type(lhs, rhs)
      ! Operator `=`.
      class(a_type_t), intent(inout) :: lhs
      class(a_type_t), intent(in)    :: rhs

      lhs%x = rhs%x
   endsubroutine assign_a_type

   function add_a_type(lhs, rhs) result( res )
      ! Operator `+`.
      class(a_type_t), intent(in)  :: lhs
      class(a_type_t), intent(in)  :: rhs
      class(a_type_t), allocatable :: res

      allocate (a_type_t :: res)
      res%x = lhs%x + rhs%x
   endfunction add_a_type
endmodule a_type_m

program polymorphic_operators_memory_leaks
   ! pass one argument to limit the loop iterations, e.g.:
   ! a.out 4 # the loop will be limited to 4 iterations
   ! useful for testing with valgrind;
   ! a.out # the loop will run for LENGHT**3 iterations

   use a_type_m

   implicit none

   character(99)  :: switch
   type(a_type_t) :: a
   type(a_type_t) :: b
   integer        :: N
   integer        :: i

   a%x = [(i, i=1, LENGTH)]
   b = a

   i = command_argument_count()
   if (i == 1) then
      call get_command_argument(1,switch)
      read(switch, *) N
   else
      N = LENGTH**3
   endif

   do i=1, N
      b = a + b ! here the `+` operator generates memory leaks
      if (mod(i,10**5) == 0) print*, i
   enddo
endprogram polymorphic_operators_memory_leaks

Reply via email to