From ljm@SLAC.Stanford.EDU  Thu Dec  7 22:40:27 1995
Received: from serv05.slac.stanford.edu (SERV05.SLAC.Stanford.EDU [134.79.16.135]) by dkuug.dk (8.6.12/8.6.12) with ESMTP id WAA01183 for <sc22wg5@dkuug.dk>; Thu, 7 Dec 1995 22:40:19 +0100
Received: from [134.79.128.74] (MOZART.SLAC.Stanford.EDU)
 by SERV05.SLAC.STANFORD.EDU (PMDF V5.0-4 #10979)
 id <01HYJ0KVJI7S000SLY@SERV05.SLAC.STANFORD.EDU>; Thu,
 07 Dec 1995 13:42:48 -0800 (PST)
Date: Thu, 07 Dec 1995 13:42:48 -0800 (PST)
Date-warning: Date header was inserted by SERV05.SLAC.STANFORD.EDU
From: ljm@SLAC.Stanford.EDU (Leonard J. Moss)
Subject: Re: (SC22WG5.967) Major flaw in Fortran-95 standard -> memory leaking
X-Sender: ljm@popserv
To: hebert@ajax.serma.cea.fr
Cc: sc22wg5@dkuug.dk
Message-id: <v02130501acec7dfc2a8d@[134.79.128.74]>
X-Envelope-to: sc22wg5@dkuug.dk
MIME-version: 1.0
Content-type: text/plain; charset="us-ascii"
Content-transfer-encoding: 7BIT

At 11:29 12/7/95, hebert@ajax.serma.cea.fr wrote:
>I discovered a major flaw in the Fortran-90 standard which is
>succeptible to cause memory leakage when derived types are allocated
>with the POINTER attribute. The simplest way to illustrate this
>problem is to use the ISO_VARYING_STRING module (ISO/IEC 1539-2)
>and to code
>
>      USE ISO_VARYING_STRING
>      TYPE(VARYING_STRING),POINTER :: TEXT
>      ALLOCATE(TEXT)
>      TEXT='ABCDE'
>      DEALLOCATE(TEXT)
>
>This simple example causes a memory leak due to the internal
>definition of the type VARYING_STRING:

This behavior of DEALLOCATE is _not_ a flaw.  Consider a slightly different
example:

        USE ISO_VARYING_STRING
        TYPE(VARYING_STRING),POINTER :: TEXT, TEXT2
        ALLOCATE(TEXT)
        TEXT='ABCDE'
        TEXT2=>TEXT
        DEALLOCATE(TEXT)

If DEALLOCATE unconditionally freed the memory used internally by the type,
then TEXT2 would be left with a dangling pointer.  Your suggested overload
procedures for DEALLOCATE are careful to check the association status of
the components first.  However, there are two things wrong with this: (1)
the association status of the pointer component may be undefined (e.g., if
a DEALLOCATE occurs without ever having executed a character assignment),
in which case the use of the ASSOCIATED function is illegal; and, (2) it is
not the way the intrinsic DEALLOCATE statement itself works (since it, too,
can not be sure of the association status of the pointer).

There are lots of ways to leak memory in Fortran 90.  _Anything_ with the
pointer attribute can leak away, not just derived types with pointer
components.  For example,

        REAL, POINTER :: A(:)
        ALLOCATE ( A(1 000 000 ) )
        NULLIFY ( A )

...and there goes 4 MB, unless the implementation does garbage collection
(which is not required).  Fortran (wisely, IMO) leaves it up to the
programmer to guard against such leaks.  I don't see the case of pointer
components as being significantly different.

Of course the varying string module uncovered a much more serious problem:
the inability to declare or allocate pointers in a known association status
essentially made it impossible for certain types of applications, such as
this module, to avoid leaking memory.  I believe this problem will be fixed
in Fortran 95 by the component initialization features (though the varying
string module may need to add a deallocate _procedure_ to permit the
careful user to clean up properly).

There is one other potential for memory leaks in Fortran 90 that I don't
think gets enough attention.  A function result can have the POINTER
attribute, which is quite useful and perfectly safe when such functions are
referenced on the RHS of a pointer assignment.  Here's an example:

        TYPE(GLARCH),POINTER :: A_GLARCH, NEW_GLARCH
        ...
        A_GLARCH => NEW_GLARCH()

The function NEW_GLARCH (presumably) allocates and initializes a new object
of type GLARCH and passes a pointer to that object to A_GLARCH.
There is no memory leak and no problem.  Suppose, however, A_GLARCH has
already been allocated and one merely wants to reinitialize it.  One might
then write an ordinary assignment:

        A_GLARCH = NEW_GLARCH()

In this case NEW_GLARCH creates a new object and copies the object itself,
not the pointer, to the space already allocated to A_GLARCH.  The pointer
to the newly allocated space is lost.  Still, this is not too different
from forgetting to DEALLOCATE an already allocated A_GLARCH before using a
pointer assignment to NEW_GLARCH to reinitialize it.  The potential for
leaks becomes more serious, however, when one considers that pointer
functions can be used in general expressions and need not involve derived
types.

Of course pointer functions do not necessarily ALLOCATE their function
result -- they can be used to point to already existing objects as well.  I
suppose this is why I was unable to convince the committee to prohibit
pointer functions in general expressions (i.e., to permit them only on the
RHS of a pointer assignment).  Nevertheless, I think it's worth reminding
people from time to time that pointer functions that ALLOCATE their result
variables must be used carefully to avoid memory leaks.  (Textbook writers
take note: I've yet to find a textbook that explicitly warns against this
particular kind of leak).

--
Leonard J. Moss <ljm@slac.stanford.edu>  | My views don't necessarily
Stanford Linear Accelerator Center       | reflect those of SLAC,
MS 97; P.O. Box 4349; Stanford, CA 94309 | Stanford or the DOE


