【问题标题】:Address Sanitizer can not detect memory leaks with option -OAddress Sanitizer 无法使用选项 -O 检测内存泄漏
【发布时间】:2017-01-09 12:08:05
【问题描述】:

当我使用Address Sanitizer(clang v3.4)来检测内存泄漏时,我发现使用-O(except -O0)选项总是会导致一个no-leak-detected结果。

代码很简单:

#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标签。
  • 你没有使用数组,也许它被优化了?
  • @BasileStarynkevitch 见clang -fsanitize=address -g -O main.cpp 行——这表明OP 正在使用C++(clang 编译器根据文件扩展名.cpp 选择语言)。 OP 的代码是有效的 C++。

标签: c++ c memory-leaks address-sanitizer


【解决方案1】:

这是因为your code is completely optimized away。生成的程序集类似于:

main:                                   # @main
    xorl    %eax, %eax
    retq

没有任何对malloc的调用,就没有内存分配......因此没有内存泄漏。


为了让 AddressSanitizer 检测内存泄漏,您可以:

  • Compile with optimizations disabled,正如 cmets 中提到的 Simon Kraemer

  • array标记为volatilepreventing 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:我认为 OP 知道这一点,因为他提到使用 -O0 编译时正确报告了内存泄漏。
【解决方案2】:

查看生成的代码。

GCC 和 Clang 实际上都知道malloc 的语义。因为在我的 Linux/Debian 系统上&lt;stdlib.h&gt; 包含

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

__attribute_malloc__ & _wur(和__THROW)是在别处定义的宏。阅读 GCC documentation 中的 Common Function Attributes 和 Clang 文档 says

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

我强烈怀疑-Omalloc 的调用通过删除它优化

在我的 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 编译。 clanggcc 都能够优化并提供一些调试信息(在优化很多时可能是“近似值”)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-16
    • 2021-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多