Oracle® Solaris Studio 12.4: Discover and Uncover User's Guide

Exit Print View

Updated: December 2015
 
 

Interpreting discover Error Messages

In some cases, discover might report an error that is not actually an error. Such cases are called false positives. The discover utility analyzes code at instrumentation time to reduce the occurrence of false positives compared to similar tools, but they might still occur in some instances. This section provides a few tips that might help you to identify and possibly avoid false positives in discover reports.

Partially Initialized Memory

You can use bit fields in C and C++ 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 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. 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 prior 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, consider this 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 the following example:

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, even though it is not used. However, because discover will see the load, it will report a load of an uninitialized variable (UMR).

The discover utility 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 discover cannot instrument 100% of your program, especially if 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 cannot detect 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 cannot detect 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 notify 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 notify 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" {
#endif

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
}
#endif

The internal discover library, which is linked with your program at instrumentation time, defines the API functions. However, when your program is not instrumented, this library is not linked and thus all calls to the API functions will cause the application to hang. Therefore, 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.