[prog] curses forms free_field

Almut Behrens almut-behrens at gmx.net
Wed May 19 21:58:36 EST 2004


On Mon, May 17, 2004 at 09:31:02PM -0500, ed orphan wrote:
> I compiled my program, px4.c, using
> gcc -Wall -W -g -o px4 px4.c -lcurses -lform
> Then used valgrind:
>  valgrind -v --leak-check=yes --show-reachable=yes px4
> The result looks questionable:
>     definitely lost:  0 bytes in 0 blocks
>    possibley lost:  0 bytes in 0 blocks
>    still reachable  35912 bytes in 158 blocks
>       suppressed:  0 bytes in 0 blocks
> What's this "still reachable" stuff about?  Does it
> mean some memory has not been returned to
> the heap properly?

The "still reachable" means that some memory - which has not been freed
properly - is theoretically still accessible at termination of the
program (via some pointer, or whatever). One of the possible reasons
could be that the pointer to the allocated memory is kept in a global
variable.

The following two miniature test programs show the difference.
Here, we delibarately do not deallocate the memory:

#include <stdlib.h>

char *p;  // global variable

int main() {
    p = (char *)malloc(0x100000);
    return 0;
}

In this case, valgrind will tell you

==14290== LEAK SUMMARY:
==14290==    definitely lost: 0 bytes in 0 blocks.
==14290==    possibly lost:   0 bytes in 0 blocks.
==14290==    still reachable: 1048576 bytes in 1 blocks.

The memory is still reachable, because the pointer is a global
variable. Global variables are kept in the program's data segment
and are still existing upon exit().

If you use a local variable for p:

#include <stdlib.h>

int main() {
    char *p;  // local variable
    p = (char *)malloc(0x100000);
    return 0;
}

you'll get:

==14308== LEAK SUMMARY:
==14308==    definitely lost: 0 bytes in 0 blocks.
==14308==    possibly lost:   1048576 bytes in 1 blocks.
==14308==    still reachable: 0 bytes in 0 blocks.

(conceptually, the local variable is out of scope when the program
exits -- physically, the respective memory location on the stack has
probably been overwritten with something else in the meantime).


If the problem is not in your code, then libncurses might well be
responsible for the 'leak' you find-- it wouldn't be the first library
where valgrind turned up some memory problem... (to see whether it's
in fact libncurses, look at what valgrind reports before the summary.
If you compile the library with -g, it'll even tell you the line
numbers to look for in the source...)

Usually, this is not a big issue, as memory allocated on the heap will
be returned to the OS anyway, when the process/program terminates.
This is a side effect of virtual memory management of all modern
operating systems: once the address space is unmapped (when the process
terminates), the memory automatically becomes available again...

IIRC, ancient Windows systems up to 3.11 had a system-global heap.
If you allocated memory from that heap, but forgot to free it before
terminating the program, the memory was irretrievably lost until the
next reboot... (which also wasn't too much of a problem, as you had to
reboot several times a day anyway ;)


To verify this empirically, just run one of the above faulty programs,
let's say, a thousand times in sequence, e.g.

perl -e "system './memleak' for (1..1000)"

Your system won't run out of memory, although this allocates 1 GB of
memory in total.

The problem with memory leakage is normally with long-running
processes, such as daemons, or large applications like browsers that
you typically don't close for a longer period of time, or frequently
called loops in a program (e.g. imagine doing a 'find' over the whole
filesystem: if the program would leak 10K per file encountered, that
could easily sum up to several hundred MB).

Of course, it's good practice to free all memory your application
allocates, and _not_ rely on some cleanup feature of the OS -- except
if there's an extraordinarily good reason for doing so.
But programmers are lazy, sometimes...

HTH,
Almut

 


More information about the Programming mailing list