|
|
prog1.c: #include <iostream.h> #include <string.h> // X is a silly class that just // remembers a single string. class X { public: void set(char *s) { rep = new char[strlen(s)]; strcpy(rep, s); } const char *get() { return rep; } private: char *rep; }; void f() { // silly function X *x = new X; x->set("hello, world!"); } X x1, x2, x3; main() { for (int i = 0; i < 3; i++) f(); }
This program has several memory leaks; we'll use fs to find them. The first step is to compile the program with -f.
CC -f -o prog1 prog1.c -lfs -l++
This inserts all the appropriate fs instrumentation code, and links in the fs run time libraries. Next we load the program into dbxtool, and run it to the beginning of main:
Let's see what's on the freestore.
There are four objects of unknown type. This may appear strange, since we haven't executed any code yet, but remember that we have executed code, static initializer code. Somewhere, some static initializers must have newed these four objects. Since the only global variables we personally define in prog1.c are of type X, and X has no constructor, it must be the case that constructors for global variables in iostream.h and string.h new these four objects. This explains why the types of the objects are unknown: the calls which newed them are contained in library archives which were not compiled with -f.
Now let's find our memory leak. This is done simply by two commands: first continue program execution all the way to the end of main, then look at the freestore.
Other than the objects newed during static initialization (which will presumably be deleted during static finalization), there are six objects left on the freestore. These are the objects that have leaked. From an examination of the symbolic information provided by fs, we find the bug easily. f is forgetting to delete the instance of X that it news. Let's insert the appropriate call.
void f() { // silly function X *x = new X; x->set("hello, world!"); delete x; }
After recompiling, we reload the program into the debugger and get execution back to the end of main. Here's what is on the freestore.
This is better, but still not correct. Even though the Xs have been deleted, the character arrays are still there. Closer examination of the symbolic information shows that these arrays were newed during construction of instances of X. It is a general principle that things newed during the construction of an object should probably be deleted during the destruction of that same object. An examination of X show that this is indeed the case here. We edit the code to give X a constructor and destructor:
class X { public: X(): rep(0) {} ~X() { delete rep; } void set(char *s) { rep = new char[strlen(s)]; strcpy(rep, s); } const char *get() { return rep; } private: char *rep; };
Once more recompiling, reloading, and stopping execution at the end of main,a click on ``fs'' displays the following:
This looks correct. The only objects left in the freestore are ones which will be deleted in static finalizers.