Search

ParaSoft

HOME
PRODUCTS
SUPPORT
ABOUT
WHAT'S NEW
EVENTS


Insure++

Quick facts

Add-on Modules:
   -INUSE
   -TCA

Comparisons

Technical Papers

Support & Manuals

FAQs

Recent Reviews

User Testimonials

Press Releases


Insure tool to debug c++





Insure++ User's Guide - Insure++ Reports

Part I



Insure++ Reports

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.

Default behavior

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.

The report file

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.)

Warning

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.

Customizing the output format

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.

Warning

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)

Displaying process information

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.

Displaying the time at which the error occurred

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>

Displaying repeated errors

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.

Limiting the number of errors

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.

Changing stack traces

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.

Searching for source code

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 (:).

Warning

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.

Suppressing error messages

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.

Suppressing error messages by context

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 * }

Suppressing Messages by File/Line

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

Suppressing C++ warning messages

C++

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.

Suppressing other warning messages

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.

Enabling error messages

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

Opaque pointers

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.

"Stretchy arrays"

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. Warning

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.

Report summaries

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. TCA
  • A "coverage" summary which indicates how much of the application's code has been executed.

None of these is displayed by default.

The "bugs" summary

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 "leak" summaries

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

TCA

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
Tools to debug c++ and java
(888) 305-0041 info@parasoft.com Copyright © 1996-2001 ParaSoft