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

Exit Print View

Updated: December 2015
 
 

discover APIs and Environment Variables

There are several discover APIs and environment variables that you can specify in your code.

discover APIs

Oracle Solaris Studio 12.4 implements six new discover functions that you can call from your program to receive memory leak and memory allocation information. These functions print the information on stderr. At the end of the program output, discover by default prints the final memory report with the memory leaks in the program. To use these APIs, the source file of the application needs to include the header file for discover: #include <discoverAPI.h>.

The functions and what they report are as follows:

discover_report_all_inuse()

Reports all memory allocations

discover_report_unreported_inuse()

Reports all memory allocations not previously reported.

discover_mark_all_inuse_as_reported()

Marks all memory allocations thus far as reported.

discover_report_all_leaks()

Reports all memory leaks.

discover_report_unreported_leaks()

Reports all memory leaks not previously reported.

discover_mark_all_leaks_as_reported()

Marks all memory leaks thus far as reported

This section describes some methods for working with discover APIs.


Note -  The discover APIs will not work with ADI mode.

Finding Memory Leaks With discover APIs

For each function specified in your code, discover reports the stack of where the memory was allocated. Memory leaks are allocated memory that is unreachable in the program.

The following example shows how to use these APIs:

$ cat -n tdata.C
     1    #include <discoverAPI.h>
     2   
     3    void foo()
     4    {
     5      int *j = new int;
     6    }
     7   
     8    int main()
     9    {
    10      foo();
    11      discover_report_all_leaks();
    12   
    13      foo();
    14      discover_report_unreported_leaks();
    15   
    16      return 0;
    17    }
$ CC -g tdata.C
$ discover -w - a.out
$ a.out

The following example shows the expected output.

******** discover_report_all_leaks() Report ********
1 allocation at 1 location left on the heap with a total size of 4 bytes
LEAK 1: 1 allocation with total size of 4 bytes 
void*operator new(unsigned) + 0x36 
void foo() + 0x5e  <tdata.C:5>
2:
3:    void foo()
4:    {
5:=>    int *j = new int;
6:    }
7:
8:    int main() 
main()+0x1a  <tdata.C:10>
9:    {
10:=>    foo();
11:      discover_report_all_leaks();           
12:   
13:      foo();         _start() + 

**********************************************************
******** discover_report_unreported_leaks() Report ********
1 allocation at 1 location left on the heap with a total size of 4 bytes
LEAK 1: 1 allocation with total size of 4 bytes 
void*operator new(unsigned) + 0x36
void foo() + 0x5e  <tdata.C:5>
2: 
3:    void foo()
4:    {
5:=>    int *j = new int;
6:    }
7:
8:int main()
main() + 0x24  <tdata.C:13>
10:      foo();
11:      discover_report_all_leaks();
12:
13:=>    foo();
14:      discover_report_unreported_leaks();
15:
16:return 0;
_start() + 0x71 

**********************************************************
***************** Discover Memory Report *****************
2 allocations at 2 locations left on the heap with a total size of 8     bytes
LEAK 1: 1 allocation with total size of 4 bytes
void*operator new(unsigned) + 0x36
void foo() + 0x5e  <tdata.C:5>
2:
3:    void foo()
4:    {
5:=>    int *j = new int;
6:    }
7:
8:    int main() 
main() +    0x1a  <tdata.C:10>
7:
8:    int main()
9:    {             10:=>    foo();
11:      discover_report_all_leaks();
12:   
13:      foo();         _start() + 0x71 
LEAK 2: 1 allocation with total size of 4 bytes
void*operator new(unsigned) + 0x36 
void foo() + 0x5e  <tdata.C:5>
2:
3:    void foo()
4:    {
5:=>    int *j = new int;
6:    }
7:
8:    int main()
main() + 0x24  <tdata.C:13>
10:      foo();
11:      discover_report_all_leaks();
12:
13:=>    foo();
14:         discover_report_unreported_leaks();
15:
16:      return 0;
_start() + 0x71 

DISCOVER SUMMARY:
unique errors   : 0 (0 total)
unique warnings : 0 (0 total)

Finding Leaks in a Server or Long-Running Program

If you have a long-running program or a server that never exits, you can call these discover functions using dbx at any time, even if you have not put the calls in your code. The program must have been run with at least the light mode of discover using the –l option. Note that dbx can attach to a running program. The following example shows how to find leaks in a long-running program.

Example 1  Finding Two Leaks in a Long Running Program

For this example, the a.out file is a long-running program with two processes, each with one leak. Each process is assigned a process ID.

The following rl script contains the commands to ask the program to report unreported memory leaks.

#!/bin/sh
dbx - $1 > /dev/null 2> &1 << END
call discover_report_unreported_leaks()
exit
END

Once you have a program and a script, you can use discover and run the program.

% discover -l -w - a.out
% a.out
8252: Parent allocation 64
8253: Child allocation 32

In a separate terminal window, you can run the script on the parent process.

% rl 8252

The program reports the following information for the parent process:

******** discover_report_unreported_leaks() Report ********

1 allocation at 1 location left on the heap with a total size of 64 bytes

    LEAK 1: 1 allocation with total size of 64 bytes
    main() + 0x1e  <xx.c:17>
        14:   
        15:      if (child > 0) {
        16:   
        17:=>      void *p = malloc(64);
        18:        printf("%jd: Parent allocation 64\n", (intmax_t)getpid());
        19:        p = 0;
        20:        for (int j=0; j < 1000; j++) sleep(1);
    _start() + 0x66


**********************************************************

Run the script again for the child process.

% rl 8253

The program reports the following information for the child process:

******** discover_report_unreported_leaks() Report ********

1 allocation at 1 location left on the heap with a total size of 32 bytes

    LEAK 1: 1 allocation with total size of 32 bytes
    main() + 0x80  <xx.c:24>
        21:      }
        22:   
        23:      else {
        24:=>      void *p = malloc(32);
        25:        printf("%jd: Child allocation 32\n", (intmax_t)getpid());
        26:        p = 0;
        27:        for (int j=0; j < 1000; j++) sleep(1);
    _start() + 0x66


**********************************************************

You can use the script repeatedly to find any new leaks.

SUNW_DISCOVER_OPTIONS Environment Variable

You can change the runtime behavior of an instrumented binary by setting the SUNW_DISCOVER_OPTIONS environment variable to a list of the command-line options –a, –A, –b, –e, –E, –f, –F, –H, –l, –L, –m, –P, –S, and –w. For example, if you want to change the number of errors reported to 50 and limit the stack depth in the report to 3, you would set the environment variable to the following:.

–e 50 –s 3

SUNW_DISCOVER_FOLLOW_FORK_MODE Environment Variable

By default, if a binary you have instrumented with discover forks while you are running it, discover continues to collect memory access error data from the parent and child processes, meaning the default behavior is both. For example. if you want discover to follow the fork and collect memory access data from the child process, set the SUNW_DISCOVER_FOLLOW_FORK_MODE environment variable to:

–F child