Insure++ User's Guide - Insure++ Reports
Part I
The error reports that have already been shown indicate that
Insure++ provides a great deal of information about the problems
encountered in your programs. It also provides many ways of
customizing the presentation of this information to suit your
needs.
By default, Insure++ adopts the following error reporting
strategy:
- Error messages are "coded" by a single word shown in
uppercase, such as
HEAP_CORRUPT ,
READ_OVERFLOW ,
LEAK_SCOPE ,
etc.
- Messages about error conditions are displayed unless they have
been suppressed by default or in a site specific configuration
file. (See "Error Codes"
for a list.)
- Only the first occurrence of a particular
(unsuppressed) error at any given source line is shown. (See "Report
summaries" for ways to change this behavior.)
- Error messages are displayed on output stream
stderr (To change this default, see
"The report file").
- Each error shows a stack trace of the previous routines, displayed
all the way back to your main program.
Normally, error reports are displayed on the UNIX stderr
I/O stream. Users interested in sending output to
Insra should consult the Insra
section of this manual. If you wish to capture both your program's output and
the Insure++ reports to a file, you can use the normal shell redirection
method. An alternative is to have Insure++ redirect only its output
directly by adding an option similar to
insure++.report_file bugs.dat
to your .psrc file. This tells Insure++ to
write its reports to the file bugs.dat , while allowing your
program's output to display as it normally would. Whenever this option is in
effect you will see a "report banner" similar to
** Insure++ messages will be written to bugs.dat **
Report Banner
on your terminal when your program starts to remind you that error
messages are being redirected. To suppress the display of this banner
add the option
insure++.report_banner off
to your .psrc file .
Normally the report file is overwritten each time your program
executes, but you can force messages to be appended
to an existing file with the command
insure++.report_overwrite false
If you wish to keep track of the reports from multiple runs of your
code, an alternative is to have Insure++ automatically generate
filenames for you based on a template that you provide. This takes the
form of a string of characters with tokens such as
"%d" , "%p" ,
or "%V" embedded in it. Each of these is
expanded to indicate a certain property of your program as indicated
in the table on Filenames.
Thus, for example, the option
insure++.report_file %v-errs.%D
when executed with a program called foo at
10:30 a.m. on the 21st of March 1997, might generate a report file with
the name
foo-errs.970321103032
(The last two digits are the seconds after 10:30 on which execution began.)
Note that programs which fork will automatically have a "
-%n " added to their format strings unless a
%n or %p token is explicitly added
to the format string by the user. This ensures that output from different
processes will always end up in different report files.
You can also include environment variables in these filenames so
that
$HOME/reports/%v-errs.%D
generates the same filename as the previous example, but also ensures
that the output is placed in the reports sub-directory of the user's
HOME .
This method is very useful for keeping track of program runs during
development to see how things are progressing as time goes on.
By default, Insure++ displays a particular
banner for each error report, which contains the
filename and line number containing the error, and the error category
found, e.g.,
[foo.c:10] **READ_UNINIT_MEM(copy)**
If you wish, you can modify this format to suit either your aesthetic
tastes or for some other purpose, such as enabling the editor in your
integrated environment to search for the correct file and line number
for each error.
Customization of this output is achieved by setting the
error_format option in your
.psrc file to a string of characters containing
embedded tokens which represent the various pieces of information that you
might wish to see. (A complete list is shown on
ERROR_FORMAT.)
For example, the command
insure++.error_format "\"%f\", line %l: %c"
would generate errors in the format
"foo.c", line 8: READ_UNINIT_MEM(copy)
which is a form recognized by editors such as
GNU emacs.
Notice how the embedded double quote characters required
backslashes to prevent them being interpreted as the end of the format
string.
A multi-line format can also be generated with a command such as
insure++.error_format "%f, line %l\n\t%c"
which might generate
foo.c, line 8
READ_UNINIT_MEM(copy)
When using Insure++ with programs that run on remote machines
(e.g., in client-server mode) or which fork into multiple processes, you might wish to
display additional process-related information in your error reports.
For example, adding the option
insure++.error_format <all> \
"%f, line %l: \n\tprocess %p@%h: %c"
to your .psrc file would generate errors in the
following form
foo.c, line 8:
process 1184@gobi: READ_UNINIT_MEM(copy)
which contains the name of the machine on which
the process is running and its process ID.
Especially when using Insure++ with applications that run for a
long period, it is often convenient to know exactly when various
errors occurred. You can extend the error reports generated by
Insure++ in this fashion by adding the '%d' and/or '%t'
characters to the error report format as specified in your
.psrc file. For example, the format
insure++.error_format "%f:%l, %d %t <%c>"
generates error reports in the form
foo.c:8, 9-Jan-97 14:24:03 <READ_NULL>
The default configuration suppresses all but the
first error of any given kind at a source line.
You can display more errors by modifying the parameter
report_limit in the
.psrc file in either your working or HOME
directory.
For example, adding the line
insure++.report_limit 5
to your .psrc file will show the first five
errors of each type at each source line.
Setting the value to zero suppresses any messages except those shown
in summaries. (See "Report
summaries".)
Setting the report_limit value to -1 shows all
errors as they occur.
Note that not all information is lost by showing only the first (or
first few) errors at any source line. If you enable the report summary
(See The "bugs" summary)
you will see the
total number of each error at each source line.
If your program is generating too many errors for convenient analysis,
you can arrange for it to exit (with a non-zero exit code) after
displaying a certain number of errors by adding the line
insure++.exit_on_error number
to your .psrc file and re-running the program.
After the indicated number of errors, the program will
exit. If number is less than or equal to zero, all errors are
displayed.
There are two potential modifications you can make to alter the
appearance of the stack tracing information presented by
Insure++ to indicate the location of an error.
By default, Insure++ will read your program's symbol table at
start-up time to get enough information to generate stack traces. To
get file and line information, you will need to compile your programs
with debugging information turned on (typically via the
-g switch). If this is a problem, Insure++ can
generate its own stack traces for files compiled with Insure++.
You can select this mode by adding the options
insure++.symbol_table off
insure++.stack_internal on
to your .psrc file.
The stack_internal
option will take effect after you recompile your program
(see STACK_INTERNAL),
while the symbol_table option
can be toggled at runtime
(see SYMBOL_TABLE).
In this case, the stack trace will display
** routines not compiled with insure **
in place of the stack trace for routines which were not compiled with
Insure++. This will also make your program run faster,
particularly at start-up, since the symbol table will not be read.
If your program has routines which are deeply nested, you may see very
long stack traces. You can reduce the amount of stack tracing
information made available by adding an option like
insure++.stack_limit 4
into your .psrc file. If you run your program again,
you will see at most1 the last
four levels of the stack trace with each error.
The value "0" is valid and effectively disables tracing.
The value "-1" is the default and indicates that the full
stack trace should be displayed, regardless of length.
Stack traces are also presented to show the function calling sequence
when blocks of dynamically allocated memory were allocated and
freed. In a manner similar to the stack_limit option,
the malloc_trace and
free_trace
options control how extensive these stack traces are.
Normally, Insure++ remembers the directory in which each source
file was compiled and looks there when trying to display lines of
source code in error messages. Occasionally your source code will no
longer exist in this directory, possibly because of some sophisticated
"build" or "make " process.
You can give Insure++ an alternative list of directories to
search for source code by adding a line such as
insure++.source_path .:$HOME/src:/usr/local/src
to the .psrc file in your current working or
HOME directories.
The list may contain any number of directories separated by either
spaces or colons (:).
Insure++'s error messages normally indicate the line of
source code responsible for a problem on the second line of an error
report, after the ">>" mark. If this line is missing
from the report, it means that the source code could not be found at
runtime.
The previous sections discussed issues which can affect the appearance
of particular error messages. Another alternative is to completely
suppress error messages of a given type which you either cannot, or
have no wish to, correct.
The simplest way of achieving this is to add lines similar to
insure++.suppress EXPR_NULL, PARM_DANGLING
to your .psrc file and re-run the program.
No suppressed error messages will be displayed, although they will
still be counted and displayed in the report summary.
(See The "bugs" summary.)
In this context, certain wild-cards can be applied so that, for
instance, you can suppress all memory leak messages with the
command
insure++.suppress LEAK_*
You can suppress all errors with the command
insure++.suppress *
which has the effect of only creating an error summary. If the error
code has sub-categories, you can disable them
explicitly by listing the sub-category codes in parentheses after the name,
e.g.,
insure++.suppress BAD_FORMAT(sign, compatible)
Alternatively,
insure++.suppress BAD_FORMAT
suppresses all sub-categories of the specified error class.
The commands described in the previous section either suppress or
enable errors in a given category regardless of where in your program
the error occurs. This syntax can be extended to
specifying particular routines which must appear in
the function call stack at the time of the error for it to be enabled or
suppressed.
For example, the command
insure++.suppress READ_NULL { sub* * }
suppresses messages of the given category which occur in any routine
whose name begins with the characters "sub ".
The interpretation of this syntax is as follows:
- The stack context is enclosed by a pair of braces.
- Routine names can either appear in full or can contain the
'*' or '?' wildcard characters. The former matches
any string, while the latter matches any single character.
- An entry consisting of a single '*' character matches
any number of functions, with any names.
- Entries in the stack context are read from left to right with the
leftmost entries appearing lowest (or most recently) in the call
stack.
With these rules in mind, the previous entry is read as
- The lowest function in the stack trace (i.e., the function
generating the error message) must have a name that begins with
"
sub " followed by any number of other characters.
- Any number of functions of any name may appear higher in the
function call stack.
A rather drastic, but common, action is to suppress any errors
generated from within calls to the X Window System libraries. If we
assume that these functions have names which begin with either
"X" or "_X", we could achieve this goal with the
statements
insure++.suppress all { * X* * }
insure++.suppress all { * _X* * }
which suppresses errors in any function (or its descendents) which
begins with either of the two sequences.
As a final example, consider a case in which we are only interested in
errors generated from the routine foobar or its
descendents. In this case, we can combine suppress
and unsuppress commands as
follows
insure++.suppress all
insure++.unsuppress all { * foobar * }
In addition to suppressions based on stack traces, you can suppress
error messages based on the file/line generating the message.
The syntax for this type of suppression is:
file:line#
in file
Examples:
suppress readbadindex at foo.h:32
This suppresses readbadindex error messages at line 32 of foo.h at both
compile-time and run-time.
suppress parserwarning in header.h
This suppresses all parser warnings in header.h .
Wildcards are not supported in filenames for this syntax. However, this
syntax can be used at both compile-time and run-time (unlike stack trace
suppressions, which can only be used at run-time).
It is illegal to have
both a stack trace suppression and a file/line suppression on the same
line, e.g.:
suppress myerror {a b c} at foo.c:3
The warning messages that Insure++ displays during parsing of
C++ code (see Insure++ Manpage) can
easily be suppressed if the user does not wish to correct the code
immediately. For example, to suppress the warning from that section,
simply add
insure++.suppress_warning 13-2
to your .psrc file and recompile. The
warning messages will no longer be displayed.
For other compile time warning messages which do not have a number
associated, there is another suppress option available. The
suppress_output option
takes a string as an argument and will suppress any message that includes
text which matches the string. For example, the option
insure++.suppress_output wrong arguments passed
would suppress the warning from the previous section, as well as any
others that included this text string.
Normally, you will be most interested in suppressing error messages
about which you can or wish to do nothing. Occasionally, however, you
will want to enable one of the options that is currently suppressed,
either by system default
(See "Error Codes")
or in one of your own .psrc files. This is achieved
by adding a line similar to the following to your .psrc file.
insure++.unsuppress RETURN_FAILURE
You can prohibit Insure++ from checking a pointer by declaring
it "opaque". You can do this for a function return value by
using the assert_ok .psrc option
(see ASSERT_OK) or, more generally, by using an
iic_opaque function in an interface. When you do this,
Insure++ will not check this pointer or any pointers which are
derived from it. This is normally done only for a third-party function
which returns a pointer to a memory block allocated in a way that will
not be seen by Insure++. This option tells Insure++ to ignore
such a pointer.
Another problem that comes up infrequently but causes problems is
"stretchy arrays". Many programmers build structures in
which the last element is an array whose size is only determined at
runtime. Consider the following code
1: /*
2: * File: stretch1.c
3: */
4: #include (stdlib.h)
5:
6: struct stretchy {
7: int nvals;
8: int data[1];
9: };
10:
11: struct stretchy *create(nvals)
12: int nvals;
13: {
14: int size;
15:
16: size = sizeof(struct stretchy) +
17: (nvals-1)*sizeof(int);
18: return (struct stretchy *)malloc(size);
19: }
20:
21: main()
22: {
23: struct stretchy *s;
24: int i;
25:
26: s = create(10);
27: for(i=0; i<10; i++) s->data[i] = 0;
28: }
Because the memory allocation in line 18 takes into account the extra
memory required for the ten elements in the array, the loop in line 27
is actually valid. Previous versions of Insure++ complained about
this line, because Insure++ saw an array definition in line 8 that
indicated that the structure element data is an array with
only a single element. Beginning with version 3.1, Insure++
automatically detects possible stretchy arrays and treats them accordingly.
For details on controlling this new capability, see the
auto_expand option.
If you turn auto_expand
to off , Insure++ will work just as it did in
earlier versions. In this situation, the simplest way to deal with the
above case is to add the option
insure++.expand struct stretchy.data
to your .psrc file. This line indicates that the
element data of all structures with tag stretchy
should be allowed to expand at runtime to match the amount of memory
allocated. This allows Insure++ to compute the actual number
of elements in the "stretchy" array correctly. Multi-
dimensional stretchy arrays must be handled in the above manner,
because they cannot be automatically detected.
An interesting exercise is to change the loop in line 27 of the above
code to
for(i=0; i<=10; i++) s->data[i] = 0;
Insure++ catches this!
The above change is provided to you as example
stretch2.c .
Elements of anonymous unions and structures
(i.e. unions and structures without a tag) cannot be marked as stretchy,
as there is no way to identify them to Insure++. If you have a
stretchy array in such a union or structure, you will need to edit your
source code to insert a tag if you want to declare the array stretchy.
Normally, you will see error messages for individual errors as your
program proceeds. Using the other options described so far, you can
enable or disable these errors or control the exact number seen at
each source line.
This technique is most often used to systematically track down each
problem, one by one.
It is often useful, however, to obtain a summary of the problems
remaining in a piece of code in order to track its progress.
Insure++ supports the following types of summary reports
- A "bug" summary which lists all outstanding bugs
according to their error codes.
- A "leak" summary which lists all memory leaks - i.e.,
places where memory is being permanently lost.
- An "outstanding" summary which lists all outstanding
memory blocks - i.e., places where memory is not being freed,
but is not leaked because a valid pointer to the block still
exists.
- A "coverage" summary which indicates how much of the
application's code has been executed.
None of these is displayed by default.
This report summary is enabled by adding the option
insure++.summarize bugs
to your .psrc file and re-running your program.
In addition to the normal error reports, you will then also see a
summary such as the one shown in Figure 7.
********************* INSURE SUMMARY *********** v4.0 **
Program : gs
Arguments : golfer.ps
Directory : /usr/trf/gsb
Compiled on : Jan 5, 1996 15:40:37
Run on : Jan 5, 1996 15:44:29
Elapsed time : 00:01:06
***********************************************************
PROBLEM SUMMARY - by type
===============
Problem Detected Suppressed
-----------------------------------------------
EXPR_BAD_RANGE 7 0
READ_UNINIT_MEM 23 0
BAD_DECL 1 0
-----------------------------------------------
TOTAL 31 0
-----------------------------------------------
PROBLEM SUMMARY - by location
===============
EXPR_BAD_RANGE: Expression exceeded range, 7 occurrences
5 at ialloc.c, 170
1 at ialloc.c, 176
1 at ialloc.c, 182
READ_UNINIT_MEM: Reading uninitialized memory, 23 occurrences
7 at gxcpath.c, 137
7 at gxcpath.c, 241
1 at gdevx.c, 424
1 at gdevxini.c, 213
2 at gdevxini.c, 221
1 at gdevxini.c, 358
1 at gdevxini.c, 359
1 at gdevxini.c, 422
1 at gdevxini.c, 454
1 at gdevxini.c, 514
BAD_DECL: Global declarations are inconsistent, 1 occurrence
1 at gdevx.c, 93
Figure 7. Sample "bugs" report
summary
The first section is a header which indicates the following information
about the program being executed
- The name of the program.
- Its command line arguments, if available.
- The directory from which the program was run.
- The time it was compiled.
- The time it was executed.
- The length of time to execute.
This information is provided so that test runs can be compared
accurately as to the arguments and directory of test. The time and
date information is supplied to correlate with bug tracking
software.
The second section gives a summary of problems detected according to
the error code and frequency. The first numeric column indicates the
number of errors detected but not suppressed. This is the total number
of errors, which may differ from the number reported, since, by
default, only the first error of any particular type is reported at
each source line. The second column indicates the number of bugs which
were not displayed at all due to "suppress"
commands.
The third section gives details of the information presented in the
second section, broken down into source files and line numbers.
The simplest memory leak summary is enabled by adding the line
insure++.summarize leaks outstanding
to your .psrc file and re-running your program.
The output indicates the memory (mis)use of
the program, as shown in Figure 8.
********************* INSURE SUMMARY ************ v4.0 **
Program : leak
Arguments :
Directory : /usr/whicken/test
Compiled on : Jan 5, 1996 15:09:05
Run on : Jan 5, 1996 15:09:31
Elapsed time : 00:00:02
************************************************************
MEMORY LEAK SUMMARY
===================
4 outstanding memory references for 45 bytes.
Leaks detected during execution
---------------------
10 bytes 1 chunk allocated at leak.c, 6
Leaks detected at exit
---------------------
10 bytes 2 chunk allocated at leak.c, 7
Outstanding allocated memory
----------------------------
15 bytes 1 chunk allocated at leak.c, 8
Figure 8. Sample "leaks" report
summary
The first section summarizes the "memory leaks" which were
detected during program execution, while the second lists leaked blocks
that were detected at program exit. These are potentially serious errors,
in that they typically represent continuously increasing use of system
resources. If the program is "leaking" memory, it is likely to
eventually exhaust the system resources and will probably crash. The first
number displayed is the total amount of memory lost at the indicated source
line, and the second is the number of chunks of memory lost. Note that
multiple chunks of different sizes may be lost at the same source
line - depending on which options you are using. To customize the report,
there are three .psrc options available:
leak_combine , leak_sort , and leak_trace .
The leak_combine option controls
how Insure++ merges information about multiple blocks. The default
behavior is to combine all information about leaks which were allocated from
locations with identical stack traces (leak_combine trace ). It
may be that you would rather combine all leaks based only on the file and
line they were allocated, independent of the stack trace leading to that
allocation. In that case, you would use leak_combine location .
Or, you may simply want one entry for each leak
(leak_combine none ).
The leak_sort option controls how
the leaks are sorted, after having been combined. The options are
none , location , trace ,
size , and frequency (size is
default). Sorting by size lets you look at the biggest
sources of leaks, sorting by frequency lets you look at the
most often occurring source of leaks, and sorting by location
provides an easy way to examine all your leaks.
The leak_trace option causes a full
stack trace of each allocation to be printed, in addition to the actual file
and line where the allocation occurred (this replaces the
detailed modifier from earlier versions of Insure++.)
This option will not work if the
malloc_trace option is non-zero
(see insure++.malloc_trace ).
The third section shows the blocks which are allocated to the program
at its termination and which have valid pointers to them. Since the
pointers allow the blocks to still be freed by the program (even
though they are not), these blocks are not actually leaked. This
section is only displayed if the outstanding keyword is
used. Normally, these blocks do not cause problems, since the
operating system will reclaim them when the program
terminates. However, if your program is intended to run for extended
periods, these blocks are potentially more serious.
The coverage summary is enabled by adding the line
insure++.summarize coverage
to your .psrc file and re-running your
program.
In addition to the normal error reports, you will see a summary
indicating how much of the application's source code has been
tested. The exact form of the output is controlled by the
.psrc file option
coverage_switches , which
specifies the command line switches passed to the tca
command to create the output.
If this variable is not set, it defaults to
insure++.coverage_switches -dS
which displays an application level summary of the test coverage such
as
COVERAGE SUMMARY
================
11 blocks untested
42 blocks tested
78% covered
For details on the formatting of this output using the
coverage_switches option, consult the manual page for
the tca command.
(See TCA or the on-line man pages with the command
"man tca" )
Footnotes
- (1)
- It is "at most" because some of the lower levels of
the trace may be hidden internally by Insure++ and not
displayed by default. These levels are still counted for the
report_limit
option.
For more information, call (888) 305-0041 or send email to:
insure@parasoft.com
Insure++
Insure++ User's Guide TOC
Insra
|