Hi,

the following is meant as a suggestion to be considered in conjunction 
with general coding rules, if adequate. Don't feel urged to answer. 
Some details may be somewhat incorrect for C++. Most of it is an 
offspring from looking at those many implementation details in 
figinset.C that I disliked.

PROBLEM

Possible heap corruption (rare cases, esp. when using fork()) or heap 
overflow and heap fragmentation as well as relatively frequent memory 
leaks when using 'new'/'delete' builtin operators or certain other 
functions and programming techniques that employ dynamic memory.

Some of the problems I've seen with LyX inline image rendering may stem 
from here. Even some sigsegvs with the new (old) 1.1.x may be related.


DESCRIPTION

"Behind the scenes" those operators eventually call malloc()/free() 
library C fns (at least gcc/emx, but I think other compilers behave in 
the same way). Similar problems occur with other functions employing 
dynamic memory. This causes fragmentated memory and needs huge heap 
sizes, so that hardware caching works inefficiently.
         While on Unix-style OS the heap is allocated and re-sized 
automatically on run-time, this is not true for other OS, where the 
static heap (as well as the static executable stack) object is usually 
sized and allocated only on compile time. In this way you can better 
cope with hardware design restrictions because of limited hardware 
memory, nowadays especially important to provide for efficient use of 
the hardware cache. Drawback is that heap overflow is more likely to 
happen compared to run-time heap management.
        (EMX/gcc (with a grain of salt) uses both models, employing 
a.out binaries in the former, OMF binaries in the latter case).

Both models have frequent problems with memory leaks if programs and 
system libraries are not 100% bug-free. (Some special headaches/bugs 
are caused by fork() emulation in conjunction with run-time re-sized 
heaps.) 

I found some *very* nice explanations of other concepts and related 
bugs relevant in this context like 'stack frames', 'static memory', 
which may be a possible solution to the described problems, by David 
Evans/W.Sh. http://www.sds.lcs.mit.edu/~evs/pldi96-abstract.html), a 
short excerpt of which I'm tempted to cite:

        "Hamlet prefers garbage collection:

Yea, from the table of my memory I'll wipe away all trivial fond 
records, all saws of books, all forms, all pressures past, that youth 
and observation copied there. 

    (Shakespeare, Hamlet. Act I, Scene v)

        Ophelia prefers explicit deallocation:

`Tis in my memory lock'd, and you yourself shall keep the key of it. 

    (Hamlet. Act I, Scene iii) 

Local variables that are not allocated dynamically are stored on a
call stack. When a function returns, its stack frame is deallocated,
destroying the storage associated with the function's local variables.
A memory error occurs if a pointer into this storage is live after
the function returns (involving stack references exported from a 
function through return values or assignments to references reachable 
from global variables or actual parameters). 

In a garbage-collected environment, there may be storage that is shared
by one or more references and never explicitly released. 

All obligations to release storage stem from primitive allocation 
routines (e.g.,malloc), and are ultimately satisfied by calls to free()
        (According to  [ANSI, 4.10.3.2], NULL may be passed to free 
without an error. On some UNIX platforms, passing NULL to free causes a 
program crash.);
the argument may be NULL and need not point to defined storage. The
parameter to free must reference an unshared object, the caller may
not use the referenced object after the call, and may not pass in
a reference to a shared object."


POSSIBLE SOLUTIONS

Try to use small and better maintainable "static inline" functions 
allocating memory objects only on their stack frame, i.e. using 
variables local to them, consistently avoiding 'new'/'delete'. Thus 
memory remains confined within block nesting and exists only during 
block life time. This should reduce most problems described at the 
beginning.

Use preferably "alloc"-style garbage collection avoiding explicit 
memory deallocation ("delete"/"free()") if this is possible.

I've no proposal for global linked list-type objects that need dynamic 
memory :(.

Greets,

        Arnd


PS: Does a tool like 'lclint' exist for C++?

Reply via email to