地址无害化工具不能检测到使用选项-O时的内存泄漏问题。

3
当我使用地址泄漏检测工具(clang v3.4)时,发现使用 -O(除了 -O0)选项总是导致无泄漏检测结果。
代码很简单:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int* array = (int *)malloc(sizeof(int) * 100);
    for (int i = 0; i < 100; i++) //Initialize
    array[i] = 0;
    return 0;
} 

使用-O0编译时,
clang -fsanitize=address -g -O0 main.cpp

它将正确检测内存。

==2978==WARNING: Trying to symbolize code, but external symbolizer is not initialized!

=================================================================
==2978==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 400 byte(s) in 1 object(s) allocated from:
    #0 0x4652f9 (/home/mrkikokiko/sdk/MemoryCheck/a.out+0x4652f9)
    #1 0x47b612 (/home/mrkikokiko/sdk/MemoryCheck/a.out+0x47b612)
    #2 0x7fce3603af44 (/lib/x86_64-linux-gnu/libc.so.6+0x21f44)

SUMMARY: AddressSanitizer: 400 byte(s) leaked in 1 allocation(s).

然而,当添加了-O时,
clang -fsanitize=address -g -O main.cpp

未检测到任何内容!我在官方文档中也没有找到相关的信息。


你的代码是C代码,不是C++代码。C++标签是错误的,应该使用C标签。 - Basile Starynkevitch
你没有使用数组,可能会被优化掉了? - Schtolc
@BasileStarynkevitch 看看这行代码 clang -fsanitize=address -g -O main.cpp - 这表明原帖作者在使用 C++ (clang 编译器根据文件扩展名 .cpp 自动选择语言)。原帖作者的代码是合法的 C++ 代码。 - M.M
2个回答

7
这是因为你的代码被完全优化掉了。生成的汇编代码类似于以下内容:
main:                                   # @main
    xorl    %eax, %eax
    retq

没有任何对malloc的调用,便没有了内存分配……因此也没有内存泄漏。
为了让AddressSanitizer检测到内存泄漏,您可以选择以下方法之一:
  • Compile with optimizations disabled, as Simon Kraemer mentioned in the comments.

  • Mark array as volatile, preventing the optimization:

     main:                                   # @main
            pushq   %rax
            movl    $400, %edi              # imm = 0x190
            callq   malloc                  # <<<<<< call to malloc
            movl    $9, %ecx
    .LBB0_1:                                # =>This Inner Loop Header: Depth=1
            movl    $0, -36(%rax,%rcx,4)
            movl    $0, -32(%rax,%rcx,4)
            movl    $0, -28(%rax,%rcx,4)
            movl    $0, -24(%rax,%rcx,4)
            movl    $0, -20(%rax,%rcx,4)
            movl    $0, -16(%rax,%rcx,4)
            movl    $0, -12(%rax,%rcx,4)
            movl    $0, -8(%rax,%rcx,4)
            movl    $0, -4(%rax,%rcx,4)
            movl    $0, (%rax,%rcx,4)
            addq    $10, %rcx
            cmpq    $109, %rcx
            jne     .LBB0_1
            xorl    %eax, %eax
            popq    %rcx
            retq
    

@SimonKraemer:我认为原帖作者已经意识到这一点,因为他提到了使用“-O0”编译时内存泄漏会被正确报告。 - Vittorio Romeo

4

查看生成的代码。

实际上,GCC和Clang都知道malloc的语义。因为在我的Linux/Debian系统中,<stdlib.h>包含了这个信息。

extern void *malloc (size_t __size) __THROW __attribute_malloc__ __wur;

“__attribute_malloc__”和“_wur”(以及“__THROW”)是在其他地方定义的宏。请阅读GCC文档中关于通用函数属性的内容,Clang文档指出

Clang旨在支持广泛的GCC扩展。

我强烈怀疑使用-O时,调用malloc会被优化掉。

在我的Linux / x86-64机器上使用clang -O -S psbshdk.c(使用clang 3.8),我确实得到了这个结果:

    .globl  main
    .align  16, 0x90
    .type   main,@function
 main:                                   # @main
    .cfi_startproc
 # BB#0:
    xorl    %eax, %eax
    retq
 .Lfunc_end0:
    .size   main, .Lfunc_end0-main
    .cfi_endproc

地址错误检测器适用于已生成的二进制文件(该文件不包含任何malloc调用)。
另外,您可以使用clang -O -g编译,然后使用valgrind,或者使用clang -O -fsanitize = address -g编译。无论是clang还是gcc都能够进行优化并提供一些调试信息(在进行大量优化时可能会“近似”)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接