JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
Oracle Solaris Studio 12.3: Discover and Uncover User's Guide     Oracle Solaris Studio 12.3 Information Library
search filter icon
search icon

Document Information


1.  Introduction

2.  Memory Error Discovery Tool (Discover)

Requirements for Using Discover

Binaries Must Be Prepared Correctly

Binaries That Use Preloading or Auditing Cannot Be Used

Binaries That Redefine Standard Memory Allocation Functions Can Be Used

Quick Start

Instrumenting a Prepared Binary

Caching Shared Libraries

Instrumenting Shared Libraries

Ignoring Libraries

Command Line Options

Output Options

Instrumentation Options

Caching Options

Other Options

bit.rc Initialization Files

SUNW_DISCOVER_OPTIONS Environment Variable


Running an Instrumented Binary

Analyzing Discover Reports

Analyzing the HTML Report

Using the Errors Tab

Using the Warnings Tab

Using the Memory Leaks Tab

Using the Control Panel

Analyzing the ASCII Report

Memory Access Errors and Warnings

Memory Access Errors


















Memory Access Warnings


Interpreting Discover Error Messages

Partially Initialized Memory

Speculative Loads

Uninstrumented Code

Limitations When Using Discover

Only Annotated Code is Instrumented

Machine Instruction Might Differ From Source Code

Compiler Options Affect the Generated Code

System Libraries Can Affect the Errors Reported

Custom Memory Management Can Affect the Accuracy of the Data

Out of Bounds Errors for Static and Automatic Arrays Cannot Be Detected

3.  Code Coverage Tool (Uncover)


Interpreting Discover Error Messages

In some cases, Discover can report an error that is not actually an error. Such cases are called false positives. Discover analyzes code at instrumentation time to reduce the occurrence of false positives compared to similar tools, but there are cases where they still occur. The following sections provide a few tips that might help you to identify and possibly avoid false positives in Discover reports.

Partially Initialized Memory

Bit fields in C and C++ allow you to create compact data types. For example:

struct my_struct {
  unsigned int valid : 1;
  char         c;

In the example, the structure member my_struct.valid takes only one bit in memory. However, on SPARC platforms, the CPU can modify memory only in bytes, so the whole byte containing struct.valid must be loaded in order to access or modify the structure member. Moreover, sometimes the compiler might find it more efficient to load several bytes (for example, a machine word of four bytes) at once. When Discover detects such a load, without additional information it assumes that all four bytes are used. And if, for example, the field my_struct.valid was initialized, but the field my_struct.c was not, and the machine word containing both fields was loaded, Discover would flag a partially initialized memory read (PIR).

Another source of false positives is initialization of a bit field. To write a part of a byte, the compiler must first generate code that loads the byte. If the byte was not written prior to a read, the result is an uninitialized memory read error (UMR).

To avoid false positives for bit fields, use the -g option or the -g0 option when compiling. These options provide extra debugging information to Discover to help it identify bit field loads and initialization, which will eliminate most false positives. If you cannot compile with the -g option for some reason, then initialize structures with a function such as memset(). For example:

struct my_struct s;
/* Initialize structure prio to use */
memset(&sm 0, sizeof(struct my_struct));

Speculative Loads

Sometimes the compiler generates a load from a known memory address under conditions where the result of the load is not valid on all program paths. This situation often occurs on SPARC platforms because such a load instruction can be placed in the delay slot of a branch instruction. For example, here is a C code fragment:

int i'
if (foo(&i) != 0) { /* foo returns nonzero if it has initialized i */
  printf("5d\n", i);

From this code, the compiler could generate code equivalent to:

int i;
int t1, t2'
t1 = foo(&i);
t2 = i; /* value in i is loaded */
if (t1 != 0) {
  printf("%d\n", t2);

Assume that in the example, the function foo() returns 0 and does not initialize i. The load from i is still generated, though not used. But the load will be seen by Discover, which will report a load of an uninitialized variable (UMR).

Discover uses dataflow analysis to identify such cases whenever possible, but sometimes they are impossible to detect.

You can reduce the occurrence of these types of false positives by compiling with a lower optimization level.

Uninstrumented Code

Sometimes it is not possible for Discover to instrument 100% of your program. Perhaps some of your code comes from an assembly language source file or a third-party library that cannot be recompiled and so cannot be instrumented. Discover has no knowledge of the memory blocks the non-instrumented code is accessing and modifying. Assume for example that a function from a third-party shared library initializes a block of memory that is later read by the main (instrumented) program. Since Discover does not know that the memory has been initialized by the library, the subsequent read generates an uninitialized memory error (UMR).

To provide a solution for such cases, the Discover API includes the following functions:

void __ped_memory_write(unsigned long addr, long size, unsigned long pc);
void __ped_memory_read(unsigned long addr, long size, unsigned long pc);
void __ped_memory_copy(unsigned long src, unsigned lond dst, long size, unsigned long pc);

You can call the API functions from your program to inform Discover of specific events such as a write to a memory area (__ped_memory_write()) or a read from a memory area (__ped_memory read()). In both cases, the starting address of the memory area is passed in the addr parameter and its size is passed in the size parameter. Set the pc parameter to 0.

Use the __ped_memory_copy function to inform Discover of memory that is being copied from one location to another. The starting address of the source memory is passed in the src parameter, the starting address of the destination area is passed in the dst parameter, and the size is passed in the size parameter. Set the pc parameter to 0.

To use the API, declare these functions in your program as weak. For example, include the following code fragment in your source code.

#ifdef __cplusplus
extern "C" {

extern void __ped_memory_write(unsigned long addr, long size, unsigned long pc);
extern void __ped_memory_read(unsigned long addr, long size, unsigned long pc);
extern void __ped_memory_copy(unsigned long src, unsigned long dst, long size, unsigned long pc);

#prgama weak __ped_memory_write
#pragma weak __ped_memory_read
#pragma weak __ped_memory_copy

#ifdef __cplusplus

The API functions are defined in the internal Discover library, which is linked with your program at instrumentation time. However, when your program is not instrumented, this library is not linked and thus all calls to the API functions will result in application hang-up. So you must disable these functions when you are not running your program under Discover. Alternatively, you can create a dynamic library with empty definitions of the API functions and link it with your program. In this case, when you run your program without Discover, your library will be used, but when you run it under Discover, the real API functions will be called automatically.