Previous Next Contents Index Doc Set Home


Runtime Checking

6


Runtime Checking (RTC) allows you to automatically detect runtime errors in an application during the development phase. RTC lets you detect runtime errors such as memory access errors and memory leak errors, and monitor memory usage.

The following topics are covered in this chapter:

Basic Concepts

page 85

Using RTC

page 87

Using Access Checking

page 87

Using Memory Use Checking

page 90

Setting Options

page 95


Basic Concepts

Because RTC is an integral debugging feature, all debugging functions such as setting breakpoints, examining variables and so on, can be used with RTC, except the Collector.

The following list briefly describes the features of RTC:

Compiling with the -g flag provides source line number correlation in the RTC error messages. RTC can also check programs compiled with the optimization -O flag. There are some special considerations with programs not compiled with the -g option. See Sun WorkShop: Command Line Utilities, "Default Suppressions" on page 127, for more information.

When to Use RTC

One way to avoid seeing a large number of errors at once is to use RTC earlier in the development cycle, as you are developing the individual modules that make up the program. Write a unit test to drive each module and use RTC incrementally to check each module one at a time. That way, you deal with a smaller number of errors at a time. When you integrate all of the modules into the full program, you are likely to encounter few new errors. When you reduce the number of errors to zero, you need to run RTC again only when you make changes to a module.

Requirements

dbx does provide an API to handle other allocators; see Sun WorkShop: Command Line Utilities, "Using Fix & Continue with RTC" on page 125.

Limitations

A possible solution is to insert special files in the executable image to handle program text areas and data areas larger than 8Mb.

For more detailed information on any aspect of RTC, see the online help.


Using RTC

To use Runtime Checking, you enable the type of checking you want to use.

To turn on the desired checking mode from the Debugging window:

   Choose Checks Enable Memuse Checking.

-or-

   Choose Checks Enable Access Checking.

In the Debugging window status area, you see an indicator that RTC is enabled.

   Choose Execute Go or click Go to start the program.
When RTC detects an error, it reports the type and location of the error and returns control to the user. You can perform any of the usual debugging activities such as setting breakpoints and examining variables.

Leak errors are reported after the program finishes execution. The Memory Use window opens with the leak and block information listed.

You can selectively suppress reporting of RTC errors using the dbx command suppress. For more information, see the dbx online help for suppress.


Using Access Checking

RTC checks whether your program accesses memory correctly by monitoring each read, write, and memory free operation.

Programs may incorrectly read or write memory in a variety of ways; these are called memory access errors. For example, the program may reference a block of memory which has been de-allocated through a free() call for a heap block, or because a function returned a pointer to a local variable. Access errors may result in wild pointers in the program and can cause incorrect program behavior, including wrong outputs and segmentation violations. Some kinds of memory access errors can be very hard to track down.

RTC maintains a table that tracks the state of each block of memory being used by the program. When the program performs a memory operation, RTC checks the operation against the state of the block of memory it involves, to determine whether the operation is valid. The possible memory states are:

The program runs normally, except that it runs slower because each memory access is checked for validity just before it actually occurs. If an invalid access is detected, the Access Checking window opens and an error message giving specific information about the error is listed. The program is then suspended and control is returned to you. If the error is not a fatal error, you can continue execution of the program. The program continues to the next error or breakpoint, whichever is detected first.

Using RTC to find memory access errors is not unlike using a compiler to find syntax errors in your program. In both cases a list of errors is produced, with each error message giving the cause of the error and the program location where the error occurred. In both cases you should fix the errors in the program starting at the top of the error list and working your way down. The reason is that one error can cause the other errors in a sort of chain reaction. The first error in the chain is therefore the "first cause," and fixing that error may also fix some subsequent errors. For example, a read from an uninitialized section of memory can create an incorrect pointer, which when dereferenced can cause another invalid read or write, which can in turn lead to other errors.

Memory Access Errors

RTC detects the following memory access errors:

For a more detailed description of each memory access error checked by RTC, see the manual Command-Line Utilities.

Understanding the Memory Access Error Report

RTC prints the following information for memory access errors:

type

Type of error.

access

Type of access attempted (read or write).

size

Address of attempted access.

addr

Size of attempted access.

detail

More detailed information about addr. For example, if 
addr is in the vicinity of the stack, then its 
position relative to the current stack pointer is 
given. If addr is in the heap, then the address, size, 
and relative position of the nearest heap block is 
given.

stack

Call stack at time of error (with batch mode).

allocation

If addr is in the heap, then the allocation trace of 
the nearest heap block is given.

location

Where the error occurred. If line number information 
is available, this information includes line number 
and function. If line numbers are not available, RTC 
provides function and address.

The following example shows a typical access error:

Read from uninitialized (rui):
Attempting to read 4 bytes at address 0xeffff67c
which is 1268 bytes above the current stack pointer
Location of error: Basic.c, line 56,
     read_uninited_memory()


Using Memory Use Checking

A memory leak is a dynamically allocated block of memory that has no pointers pointing to it anywhere in the data space of the program. Such blocks are orphaned memory. Because there are no pointers to the blocks, the program cannot even reference them, much less free them. RTC finds and reports such blocks.

Memory leaks result in increased virtual memory consumption and generally result in memory fragmentation. This may slow down the performance of your program and the whole system.

Typically, memory leaks occur because allocated memory is not freed and you lose a pointer to the allocated block. Here are some examples of memory leaks:





No free of s. Once foo 
returns, there is no     
pointer pointing to the 
malloc'ed block, so that 
block is leaked.
void
foo()
{
    char *s;
    s = (char *) malloc(32);
 
    strcpy(s, "hello world");
 
    return; /* }
}

A leak can result from incorrect use of an API:

libc function getcwd() 
returns a pointer to the 
malloc'ed area when the 
first argument is NULL. 
The program should 
remember to free this. 
In this case, the block 
is not freed and results 
in a leak.
void
printcwd()
{

    printf("cwd = %s\n", getcwd(NULL, MAXPATHLEN));

    return;
}

Memory leaks can be avoided by following a good programming practice of always freeing memory when it is no longer needed and paying close attention to library functions which return allocated memory. If you use such functions, remember to free up the memory appropriately.

Sometimes, the term "memory leak" is used to refer to any block that has not been freed. This is a much less useful definition of a memory leak, because it is a common programming practice not to free memory if the program will terminate shortly anyway. RTC does not report a block as a leak if the program still retains one or more pointers to it.

Possible Leaks

There are two cases where RTC may report a "possible" leak. The first case is when no pointers were found pointing to the beginning of the block, but a pointer found pointing to the interior of the block. This case is reported as an Address in Block (aib) error. If it was a stray pointer that happened to point into the block, this would be a real memory leak. However, some programs deliberately move the only pointer to an array back and forth as needed to access its entries. In this case it would not be a memory leak. Because RTC cannot distinguish these two cases, it reports them as possible leaks, allowing the user to make the determination.

The second type of possible leak occurs when no pointers to a block were found in the data space, but a pointer was found in a register. This case is reported as an Address in Register (air) error. If the register happens to point to the block accidentally, or if it is an old copy of a memory pointer that has since been lost, then this is a real leak. However, the compiler can optimize references and place the only pointer to a block in a register without ever writing the pointer to memory. In such cases, this would not be a real leak. In all other cases, it is likely to be a real leak.


Note - RTC leak checking requires use of the standard libc malloc/free/realloc functions or allocators based on those functions

Checking for Leaks

If memory leaks checking is turned on, a scan for memory leaks is automatically performed just before the program being tested exits. Any detected leaks are reported. The program should not be killed with the kill command. Here is a typical memory leak error message:

Memory leak (mel):
Found leaked block of size 6 at address 0x21718
At time of allocation, the call stack was:
[1] foo() at line 63 in test.c
[2] main() at line 47 in test.c

Clicking on the call stack location hypertext link takes you to that line of the source code in the editor window.

UNIX programs have a main procedure (called MAIN in f77) which is the top-level user function for the program. Normally, a program terminates either by calling exit(3) or by simply returning from main. In the latter case, all variables local to main go out of scope after the return, and any heap blocks they pointed to are reported as leaks (unless globals point to those same blocks).

It is a common programming practice not to free heap blocks allocated to local variables in main, because the program is about to terminate anyway, and then return from main without calling (exit()). To prevent RTC from reporting such blocks as memory leaks, stop the program just before main returns by setting a breakpoint on the last executable source line in main. When the program halts there, use the RTC showleaks command to report all the true leaks, omitting the leaks that would result merely from main's variables going out of scope.

Detecting Memory Leak Errors


Note - RTC only finds leaks of malloc memory. If your program does not use malloc, RTC cannot find memory leaks.
RTC detects the following memory leak errors:

For a more detailed description of each memory leak error RTC reports, see the Command-Line Utilities manual.

Memory Use Error Reporting

You have two choices for reporting memory blocks, a summary report and a detailed report.

To switch report types:

1. From the Debugging window, choose Windows Memory Use Checking.

2. From the Leaks menu or the Blocks menu, choose Summary Report or Detailed Report to toggle on the report option you want to use.

You can also set your default reporting option using the Debugging Options dialog box. See "Setting Options" on page 95 for more information.

Memory Use Error Types

Both reports include the following information for memory leak errors:

location

location where leaked block was allocated

addr

address of leaked block

size

size of leaked block

stack

call stack at time of allocation, as constrained by check -frames.

Because the number of individual leaks can be very large, RTC automatically combines leaks that were allocated at the same place into a single combined leak report.

However, the summary report capsulizes the error information into a table, while the detailed report gives you a separate error message for each error. They both contain a hypertext link to the location of the error in the source code.

Detailed Leak Report

A typical detailed report contains the following:

Actual leaks report    (actual leaks:   1 total size: 16 bytes)
Memory leak (mel):
Found leaked block of size 16 bytes at address 0x21590
At time of allocation, the call stack was:
            main

Possible leaks report  (possible leaks:  0 total size:   0 bytes)

Blocks in use report   (blocks in use:   0 total size:   0 bytes)

Summary Leak Report

When you use a summary report, the error information is summarized, and displayed as follows:

Actual leaks report    (actual leaks:  1    total size:   16 bytes)
Total Num of Leaked Allocation call stack
Size  Blocks Block   Address
===== ===== ======= =======================
 16     1    0x21590  main

The location on the call stack is a blue hypertext link that takes you to the appropriate place on the stack.


Setting Options

You can set options to control the reporting operation of RTC.

To set Debugging Runtime Checking options:

   Choose Debug Debugging Options.
   Choose Category Runtime Checking.
When you set an option here, you can choose to apply it to the current debugging session by clicking OK, or you can save it as the new default by clicking Save As Default and then clicking OK.

Access Checking Reporting

Automatic blocks report at exit
Sets whether your blocks report for Access Checking is automatically generated in detailed or summary form at program exit, or if no report is generated.

Automatic leaks report at exit
Sets whether your leaks report for Access Checking is automatically generated in detailed or summary form at program exit, or if no report is generated.

Error Reporting

Max. errors to report
Sets the maximum number of errors that RTC reports. The default is 1000.

The error limit is used separately for access errors and leak errors. For example, if the error limit is set to 5, then a maximum of 5 access errors and 5 memory leaks are shown in the report at the end of the run.

Log errors to file and continue
Causes RTC not to stop upon finding an error, but to continue running. The program stops when breakpoints are encountered or if the program is interrupted.

All errors are redirected to the default file /tmp/dbx.errlog.<pid>. You can select a different file to save errors to. To redirect all errors to the terminal, set the filename to /dev/tty.


Note - If the filename filename, already exists, the contents of that file are erased before output is redirected to that file.
Suppress duplicate error messages
Causes a particular error at a particular location to be reported only the first time it is encountered. This is useful for preventing multiple copies of the same error report when an error occurs in a loop which is executed many times.




Previous Next Contents Index Doc Set Home