Oracle Solaris Studio 12.2 Discover 和 Uncover 用户指南

分析 Discover 报告

Discover 报告提供的信息可帮助您有效地定位并修复源代码中的问题。

缺省情况下,该报告以 HTML 格式写入到 output_file.html,其中 output_file 是校验过的二进制文件的基本名称。该文件位于您运行校验过的二进制文件时所在的工作目录中。

校验二进制文件时,可以使用 -H 选项请求将 HTML 输出写入指定的文件,或使用 -w 选项请求将其写入文本文件(请参见命令行选项)。

校验二进制文件后,可以更改SUNW_DISCOVER_OPTIONS 环境变量中报告的 -H-w 的设置。例如,如果希望在以后运行程序时将报告写入不同的文件,可以执行此操作。

分析 HTML 报告

使用 HTML 报告格式可以对程序进行交互分析。开发人员可以通过使用电子邮件或者通过发布到 Web 页上来轻松共享 HTML 格式的数据。HTML 报告与 JavaScript 交互功能相结合,使得用户可以轻松浏览 Discover 消息。

"Errors"(错误)选项卡(请参见使用 "Errors"(错误)选项卡)、"Warnings"(警告)选项卡(请参见使用 "Warnings"(警告)选项卡)和 "Memory Leaks"(内存泄漏)选项卡(请参见使用 "Memory Leaks"(内存泄漏)选项卡)分别用于浏览错误消息、警告消息和内存泄漏报告。

使用左侧的控制面板(请参见使用控制面板)可以更改当前显示在右侧的选项卡内容。

使用 "Errors"(错误)选项卡

在浏览器中首次打开 HTML 报告时,"Errors"(错误)选项卡处于选中状态,并显示执行校验过的二进制文件期间发生的内存访问错误列表。

Discover HTML 报告的 "Errors"(错误)选项卡

单击某个错误时,将显示发生该错误时的栈跟踪:

Discover HTML 报告的 "Errors"(错误)选项卡(包含栈跟踪)

如果代码是使用 -g 选项编译的,可以通过单击栈跟踪中的每个函数来查看相应函数的源代码:

Discover HTML 报告的 "Errors"(错误)选项卡(包含源代码)

使用 "Warnings"(警告)选项卡

"Warnings"(警告)选项卡显示了有关可能的访问错误的所有警告消息。单击某个警告时,将显示发生该警告时的栈跟踪。如果代码是使用 -g 选项编译的,可以通过单击栈跟踪中的每个函数来查看相应函数的源代码。

Discover HTML 报告的 "Warnings"(警告)选项卡(包括栈跟踪和源代码)

使用 "Memory Leaks"(内存泄漏)选项卡

"Memory Leaks"(内存泄漏)选项卡的顶部显示程序运行结束时仍保持已分配状态的总块数,并在下方列出了相应的块。

Discover HTML 报告的 "Memory Leaks"(内存泄漏)选项卡

单击某个块时,将显示该块的栈跟踪。如果代码是使用 -g 选项编译的,可以通过单击栈跟踪中的每个函数来查看相应函数的源代码。

Discover HTML 报告的 "Memory Leaks"(内存泄漏)选项卡(包括栈跟踪和源代码)

使用控制面板

要查看所有错误、警告和内存泄漏的栈跟踪,请在控制面板的 "Stack Traces"(栈跟踪)部分中单击 "Expand All"(全部展开)。要查看所有函数的源代码,请在控制面板的 "Source Code"(源代码)部分中单击 "Expand All"(全部展开)。

要隐藏所有错误、警告和内存泄漏的栈跟踪或源代码,请单击相应的 "Collapse All"(全部折叠)。

选择 "Errors"(错误)选项卡后,将显示控制面板的 "Show Errors"(显示错误)部分,可以用来控制要显示的错误类型。缺省情况下,所有检测到的错误的复选框均处于选中状态。要隐藏某种错误类型,请单击对应的复选框以移除复选标记。

选择 "Warning"(警告)选项卡后,将显示控制面板的 "Show Warnings"(显示警告)部分,可以用来控制要显示的警告类型。缺省情况下,所有检测到的警告的复选框均处于选中状态。要隐藏某种警告类型,请单击对应的复选框以移除复选标记。

控制面板的底部显示了报告摘要,其中列出了错误和警告总数,以及泄漏的内存量。

分析 ASCII 报告

按脚本进行处理时,或者无权访问 Web 浏览器时,适合使用 ASCII(文本)格式的 Discover 报告。下面是 ASCII 报告的一个示例。


$ a.out

ERROR 1 (UAW): writing to unallocated memory at address 0x50088 (4 bytes) at:
   main() + 0x2a0  <ui.c:20>
       17:     t = malloc(32);
       18:     printf("hello\n");
       19:     for (int i=0; i<100;i++)
       20:=>    t[32] = 234; // UAW
       21:     printf("%d\n", t[2]);   //UMR
       22:     foo();
       23:     bar();
   _start() + 0x108
ERROR 2 (UMR): accessing uninitialized data from address 0x50010 (4 bytes) at:
   main() + 0x16c  <ui.c:21>$
       18:     printf("hello\n");
       19:     for (int i=0; i<100;i++)
       20:      t[32] = 234; // UAW
       21:=>   printf("%d\n", t[2]);   //UMR
       22:     foo();
       23:     bar();
       24:    }
   _start() + 0x108
       was allocated at (32 bytes):
   main() + 0x24  <ui.c:17>
       14:     x = (int*)malloc(size); // AZS warning
       15:    }
       16:    int main() {
       17:=>   t = malloc(32);
       18:     printf("hello\n");
       19:     for (int i=0; i<100;i++)
       20:      t[32] = 234; // UAW
   _start() + 0x108
0
WARNING 1 (AZS): allocating zero size memory block at:
   foo() + 0xf4  <ui.c:14>
       11:    void foo() {
       12:     x = malloc(128);
       13:     free(x);
       14:=>   x = (int*)malloc(size); // AZS warning
       15:    }
       16:    int main() {
       17:     t = malloc(32);
   main() + 0x18c  <ui.c:22>
       19:     for (int i=0; i<100;i++)
       20:      t[32] = 234; // UAW
       21:     printf("%d\n", t[2]);   //UMR
       22:=>   foo();
       23:     bar();
       24:    }
   _start() + 0x108

***************** Discover Memory Report *****************

1 block at 1 location left allocated on heap with a total size of 128 bytes

   1 block with total size of 128 bytes
   bar() + 0x24  <ui.c:9>
       6:           7:    void bar() {
        8:     int *y;
        9:=>   y = malloc(128);  // Memory leak
       10:    }
       11:    void foo() {
       12:     x = malloc(128);
   main() + 0x194  <ui.c:23>
       20:      t[32] = 234; // UAW
       21:     printf("%d\n", t[2]);   //UMR
       22:     foo();
       23:=>   bar();
       24:    }
   _start() + 0x108

ERROR 1: repeats 100 times
DISCOVER SUMMARY:
   unique errors   : 2 (101 total, 0 filtered)
   unique warnings : 1 (1 total, 0 filtered)

该报告包括错误和警告消息,其后是摘要。

错误消息以 ERROR 一词开头,并包含一个三字母代码、一个 ID 编号以及错误描述(本例中为 writing to unallocated memory)。其他详细信息包括访问的内存地址,以及读取或写入的字节数。在描述的后面,是发生错误时的栈跟踪,可以根据栈跟踪在进程生命周期中定位错误的位置。

如果程序是使用 -g 选项编译的,栈跟踪将包括源文件名称和行号。如果源文件可访问,则输出错误位置附近的源代码。每一帧中的目标源代码行均以符号 => 表示。

如果同一内存位置重复出现字节数相同的同一错误类型,完整的消息(包括栈跟踪)仅输出一次。对于多次出现的每个相同错误,会统计后续的错误,并在报告的末尾列出重复计数(如下例中所示)。


ERROR 1: repeats 100 times

如果出错内存访问的地址位于堆上,则在栈跟踪的后面输出相应堆块的信息。这些信息包括块的起始地址和大小,以及分配该块时的栈跟踪。如果该块已释放,将还包括解除分配点的栈跟踪。

警告消息的输出格式与错误消息相同,只不过是以 WARNING 一词开头。一般来说,这些消息只是提醒您注意那些不会影响应用程序正确性的情况,但提供的有用信息可帮助您改进程序。例如,分配大小为零的内存不会造成损害,但如果经常这样做可能会降低性能。

内存泄漏报告包含有关在堆上分配的、但程序退出时未释放的内存块的信息。下面是内存泄漏报告的一个示例。


$ DISCOVER_MEMORY_LEAKS=1 ./a.out
...
***************** Discover Memory Report *****************

2 blocks left allocated on heap with total size of 44 bytes
    block at 0x50008 (40 bytes long) was allocated at:
        malloc() + 0x168 [libdiscover.so:0xea54]
        f() + 0x1c [a.out:0x3001c]
          <discover_example.c:9>:
                 8:    {
                 9:=>    int *a = (int *)malloc( n * sizeof(int) );
                10:      int i, j, k;
        main() + 0x1c [a.out:0x304a8]
          <discover_example.c:33>:
                32:      /* Print first N=10 Fibonacci numbers */
                33:=>    a = f(N);
                34:      printf("First %d Fibonacci numbers:\n", N);
        _start() + 0x5c [a.out:0x105a8]
...

标题下面的第一行汇总了在堆上保持已分配状态的堆块数及其总大小。报告的大小是从开发人员的立场提供的,也就是说,不包括内存分配器的簿记系统开销。

内存泄漏摘要的后面输出了每个未释放堆块及其分配点栈跟踪的详细信息。该栈跟踪报告类似于前面介绍错误和警告消息时提到的栈跟踪报告。

Discover 报告的结尾是总摘要。该摘要报告了唯一警告和错误的数目,并在括号中提供了错误和警告的总数(包括重复项)。例如:


DISCOVER SUMMARY:
        unique errors   : 3 (3 total)
        unique warnings : 1 (5 total)