C.4.3.  Finding Memory Errors

[ fromfile: findingmemoryerrors.xml id: findingmemoryerrors ]

debugging/wrongdelete> g++ -g -Wall wrongdelete.cpp
debugging/wrongdelete> ./a.out
debugging/wrongdelete>
src/debugging> valgrind a.out
--3332-- DWARF2 CFI reader: unhandled CFI instruction 0:50
--3332-- DWARF2 CFI reader: unhandled CFI instruction 0:50
 Mismatched free() / delete / delete []
    at 0x401C1CB: operator delete(void*) (vg_replace_malloc.c:246)
    by 0x80484BD: badpointer1(int*, int) (wrongdelete.cpp:3)
    by 0x80484F4: main (wrongdelete.cpp:9)
  Address 0x4277028 is 0 bytes inside a block of size 16 alloc'd
    at 0x401BBF4: operator new[](unsigned) (vg_replace_malloc.c:197)
    by 0x80484AC: badpointer1(int*, int) (wrongdelete.cpp:2)
    by 0x80484F4: main (wrongdelete.cpp:9)

Example C.6. src/debugging/valgrind-test.cpp

#include <iostream>

int badpointer2(int k) {
  int* ip = new int[3];
  ip[0] = k;
  return ip[3];                   1
}                                 2


int main() {
  using namespace std;
  int* iptr;                      3
  int num(4), k;                  4
  cout << iptr[num-1] << endl;    5
  cout << badpointer2(k) << endl; 6
}

1

Out of bounds index

2

Memory leak: allocated memory is no longer accessible.

3

iptr is uninitialized.

4

k is uninitialized.

5

What is the state of iptr?

6

Sending uninitialized arg to function.


 For more details, rerun with: -v

--2164-- DWARF2 CFI reader: unhandled CFI instruction 0:50
--2164-- DWARF2 CFI reader: unhandled CFI instruction 0:50
 Use of uninitialised value of size 4
    at 0x80486AF: main (valgrind-test.cpp:17)
68500558

 Invalid read of size 4
    at 0x804867C: badpointer2(int) (valgrind-test.cpp:8)
    by 0x80486DD: main (valgrind-test.cpp:18)
  Address 0x4277034 is 0 bytes after a block of size 12 alloc'd
    at 0x401BBF4: operator new[](unsigned) (vg_replace_malloc.c:197)
    by 0x8048667: badpointer2(int) (valgrind-test.cpp:6)
    by 0x80486DD: main (valgrind-test.cpp:18)
0

 ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 19 from 1)
 malloc/free: in use at exit: 12 bytes in 1 blocks.
 malloc/free: 1 allocs, 0 frees, 12 bytes allocated.
 For counts of detected errors, rerun with: -v
 searching for pointers to 1 not-freed blocks.
 checked 120,048 bytes.

 LEAK SUMMARY:
    definitely lost: 12 bytes in 1 blocks.
      possibly lost: 0 bytes in 0 blocks.
    still reachable: 0 bytes in 0 blocks.
         suppressed: 0 bytes in 0 blocks.
 Use --leak-check=full to see details of leaked memory.

Example C.7. src/debugging/valgrind-test2.cpp

#include <iostream>

int notSoBadPointer(int k) {
  int* ip = new int[3];
  ip[0] = k;  
  delete[] ip;                    1
  return k;                       2
}  


int main() {
  using namespace std;
  int* iptr;                      3
  int num(4), k(4);               4
  cout << iptr[num-1] << endl;    5
  cout << notSoBadPointer(k) << endl;
}

1

Clean up memory leak.

2

A returnable value.

3

Uninitialized pointer!

4

At least k is no longer uninitialized.

5

Here's trouble!


src/debugging> g++ -g -Wall valgrind-test2.cpp
src/debugging> ./a.out
-1078391036
4
src/debugging> valgrind ./a.out
 For more details, rerun with: -v

 Use of uninitialised value of size 4
    at 0x8048794: main (valgrind-test2.cpp:18)
-1096641724
4

 ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 18 from 1)
 malloc/free: in use at exit: 0 bytes in 0 blocks.
 malloc/free: 1 allocs, 1 frees, 12 bytes allocated.
 For counts of detected errors, rerun with: -v
 All heap blocks were freed -- no leaks are possible.
src/debugging>    

Example C.8. src/debugging/valgrind-test3.cpp

#include <iostream>

int notSoBadPointer(int k) {
  int* ip = new int[3];
  ip[0] = k;  
  delete[] ip;                    1
  return k;                       2
}  


int main() {
  using namespace std;
  int num(4), k(4);               3
  int* iptr = new int[num] ;      4
  for (int i = 0; i < num; ++i)
     iptr[i] = i;
  cout << iptr[num-1] << endl;    5
  cout << notSoBadPointer(k) << endl;
  delete[] iptr;
}

1

Clean up memory leak.

2

A returnable value.

3

At least k is no longer uninitialized.

4

No longer uninitialized pointer.

5

No more trouble!


src/debugging> g++ -g -Wall valgrind-test3.cpp
src/debugging> ./a.out
3
4
src/debugging> valgrind ./a.out
3
4

 ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 18 from 1)
 malloc/free: in use at exit: 0 bytes in 0 blocks.
 malloc/free: 2 allocs, 2 frees, 28 bytes allocated.
 For counts of detected errors, rerun with: -v
 All heap blocks were freed -- no leaks are possible.
src/debugging>       

valgrind is not readily available for MacOSX[94] but the Mac Developer Tools include a graphical tool, called MallocDebug.app, that can replace a number of valgrind's functions.



[94] It can be installed from source code, which you can find at http://valgrind.org/downloads/repository.html.