In this section:
Overview
Error messages generated by Insure++ identify most programming problems, but it will sometimes be useful to have direct access to the information known to Insure++. This can be useful in the following situations:
- You are running your program from a debugger and would like to cause a breakpoint whenever Insure++ discovers a problem.
- You are tracing an error using the debugger and would like to monitor what Insure++ knows about your code.
- You wish to add calls to your program to periodically check the status of some data.
Insure++ is a debugger program and requires symbol table information. Always use debug builds instead of release builds during compiling and linking. Otherwise, applications will be compiled without the /Zi flag and linked without the /DEBUG flag, which results in unreported errors.
Available Functions
Whenever Insure++ detects an error, it prints a diagnostic message and then calls the routine _Insure_trap_error
. This is a good place to insert a breakpoint if you are working with a debugger.
The following functions show the current status of memory and can be called either from your program or the debugger. Remember to add prototypes for the functions you use, particularly if you are calling these C functions from C++ code.
void _Insure_mem_info(void *pmem);
Displays information that is known about the block of memory at address pmem
. Returns zero.
void _Insure_ptr_info(void **pptr);
Displays information about the pointer at the indicated address. Returns zero.
The following function lists all currently allocated memory blocks, including the line number at which they were allocated. It can be called directly from your program or from the debugger.
size_t _Insure_list_allocated_memory(unsigned int mode);
Use the following options to select a mode:
0
- Just the total allocation1
- “Newly-Allocated” or reallocated blocks2
- Everything
See also void _Insure_new_leak_summary().
Example Debugging Session (Unix)
The instructions in this example assume that the debugger you are using is similar to gdb. If you are using another debugger, similar commands should be available.
This example uses the following code:
/* * File: bugsfunc.c */ #include <stdlib.h> main() { char *p, *q; p = (char *)malloc(100); q = "testing"; while(*q) *p++ = *q++; free(p); return (0); }
Begin by compiling this code with Insure++ using the -Zi option
and start the debugger in the normal manner.
$ gdb bugsfunc GNU gdb 5.1 Copyright 2001 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu"... (gdb) break main Breakpoint 1 at 0x80499e6: file bugsfunc.c, line 7. (gdb) run Starting program: /home/Insure++/examples/c/bugsfunc Breakpoint 1, main (_Insight_argc=1, _Insight_argv=0xbffff004) at bugsfunc.c:7 7{
In general, adding a breakpoint in _Insure_trap_error
is useful because it enables you to take control of the program whenever an error occurs. In this case, we run the program to the error location with the following result:
(gdb) break _Insure_trap_error Breakpoint 2 at 0x40143017: file UserInterface.cc, line 303.
Setting a breakpoint per this example may not work if you have linked against the shared Insure++ libraries (the default). If you cannot set a breakpoint as shown above, it is because the shared libraries are not loaded by the debugger until the program begins to run. You can avoid this problem by setting a breakpoint on main
and running the program until that breakpoint is hit, then setting the breakpoint on _Insure_trap_error
.
(gdb) c Continuing. [bugsfunc.c:15] **FREE_BODY** >> free(p); Freeing memory block from body: p Pointer : 0x0804b9cf In block : 0x0804b9c8 thru 0x0804ba2b (100 bytes) p, allocated at bugsfunc.c, 10 main() bugsfunc.c, 10 Stack trace where the error occurred: main() bugsfunc.c, 15 **Memory corrupted. Program may crash!!** Breakpoint 2, _Insure_trap_error () at UserInterface.cc:303 303 } Current language: auto; currently c++ (gdb)
The program is attempting to free a block of memory by passing a pointer that doesn’t indicate the start of an allocated block. The error message shown by Insure++ identifies the location at which the block was allocated and also shows us that the variable p
has been changed to point to the middle of the block, but it doesn’t tell us where the value of p
changed.
We can use the Insure++ functions from the debugger to help track this down. Since the program is already in the debugger, we can simply add a breakpoint back in main
and restart it.
$ gdb bugsfunc GNU gdb 5.1 Copyright 2001 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu"... (gdb) break bugsfunc.c:10 Breakpoint 1 at 0x80499ed: file bugsfunc.c, line 10. (gdb) run Starting program: /home/Insure++/examples/c/bugsfunc Breakpoint 1, main (_Insight_argc=1, _Insight_argv=0xbffff004) at bugsfunc.c:10 10 p = (char *)malloc(100); (gdb) call _Insure_ptr_info(&p) Pointer : 0xefbeadde (uninitialized)
To see what is currently known about the pointers p
and q
, we can use the _Insure_ptr_info
function. This function expect the address of the pointer to be passed, not the pointer, itself. To see the contents of the memory indicated by the pointers, use the _Insure_mem_info
function.
(gdb) call _Insure_ptr_info(&p) Pointer : 0xefbeadde (uninitialized) (gdb) call _Insure_ptr_info(&q) Pointer : 0xefbeadde (uninitialized)
Both pointers are currently uninitialized, as would be expected. To see something more interesting, we can continue to line 13 and repeat the previous steps.
Breakpoint 2, main () at bugsfunc.c:13 13 while(*q) *p++ = *q++; (gdb) call _Insure_ptr_info(&p) Pointer : 0x0804b090 (heap) Offset : 0 bytes In Block: 0x0804b090 thru 0x0804b0f3 (100 bytes) p, allocated at bugsfunc.c, 10 malloc() (interface) main() bugsfunc.c, 10
The variable p
now points to a block of allocated memory. You can check on all allocated memory by calling _Insure_list_allocated_memory
.
(gdb) call _Insure_list_allocated_memory(2) 1 allocated memory block, occupying 100 bytes. 0x0804b090 thru 0x0804b0f3 (100 bytes) p, allocated at bugsfunc.c, 10 malloc() (interface) main() bugsfunc.c, 10
Finally, we check on the second pointer q
.
(gdb) call _Insure_ptr_info(&q) Pointer : 0x08049500 (global) Offset : 0 bytes In Block: 0x08049500 thru 0x08049507 (8 bytes) block declared at bugsfunc.c, 12
Everything seems OK at this point, so we can continue to the point at which the memory is freed and check again.
Breakpoint 3, main () at bugsfunc.c:15 15 free(p); (gdb) call _Insure_ptr_info(&q) Pointer : 0x08049507 (global) Offset : 7 bytes In Block: 0x08049500 thru 0x08049507 (8 bytes) block declared at bugsfunc.c, 12
The critical information here is that the pointer now points to an offset 7 bytes from the beginning of the allocated block. Executing the next statement, free(p)
, will now cause the previously shown error. This is because the pointer doesn’t point to the beginning of the allocated block anymore. Everything was correct at line 12 but is broken at line 15, so it is simple to find the problem in line 13, where pointer p
is incremented while looping over q
.