Address Sanitizer 无法使用选项 -O 检测内存泄漏
Address Sanitizer can not detect memory leaks with option -O
当我使用Address Sanitizer(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
未检测到任何内容!我在官方文档中没有找到任何相关信息。
查看生成的代码。
GCC 和 Clang 实际上都知道 malloc
的语义。因为在我的 Linux/Debian 系统上 <stdlib.h>
包含
extern void *malloc (size_t __size) __THROW __attribute_malloc__ __wur;
和__attribute_malloc__
& _wur
(和__THROW
)是在别处定义的宏。了解 Common Function Attributes in GCC documentation, and Clang documentation says:
Clang aims to support a broad range of GCC extensions.
我强烈怀疑 -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
都可以优化并提供一些调试信息(优化很多时可能是 "approximate")。
这是因为your code is completely optimized away。生成的程序集类似于:
main: # @main
xorl %eax, %eax
retq
没有调用 malloc
,没有内存分配...因此没有内存泄漏。
为了让 AddressSanitizer 检测内存泄漏,您可以:
将 array
标记为 volatile
, preventing the optimization:
main: # @main
pushq %rax
movl 0, %edi # imm = 0x190
callq malloc # <<<<<< call to malloc
movl , %ecx
.LBB0_1: # =>This Inner Loop Header: Depth=1
movl [=11=], -36(%rax,%rcx,4)
movl [=11=], -32(%rax,%rcx,4)
movl [=11=], -28(%rax,%rcx,4)
movl [=11=], -24(%rax,%rcx,4)
movl [=11=], -20(%rax,%rcx,4)
movl [=11=], -16(%rax,%rcx,4)
movl [=11=], -12(%rax,%rcx,4)
movl [=11=], -8(%rax,%rcx,4)
movl [=11=], -4(%rax,%rcx,4)
movl [=11=], (%rax,%rcx,4)
addq , %rcx
cmpq 9, %rcx
jne .LBB0_1
xorl %eax, %eax
popq %rcx
retq
当我使用Address Sanitizer(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
未检测到任何内容!我在官方文档中没有找到任何相关信息。
查看生成的代码。
GCC 和 Clang 实际上都知道 malloc
的语义。因为在我的 Linux/Debian 系统上 <stdlib.h>
包含
extern void *malloc (size_t __size) __THROW __attribute_malloc__ __wur;
和__attribute_malloc__
& _wur
(和__THROW
)是在别处定义的宏。了解 Common Function Attributes in GCC documentation, and Clang documentation says:
Clang aims to support a broad range of GCC extensions.
我强烈怀疑 -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
都可以优化并提供一些调试信息(优化很多时可能是 "approximate")。
这是因为your code is completely optimized away。生成的程序集类似于:
main: # @main
xorl %eax, %eax
retq
没有调用 malloc
,没有内存分配...因此没有内存泄漏。
为了让 AddressSanitizer 检测内存泄漏,您可以:
将
array
标记为volatile
, preventing the optimization:main: # @main pushq %rax movl 0, %edi # imm = 0x190 callq malloc # <<<<<< call to malloc movl , %ecx .LBB0_1: # =>This Inner Loop Header: Depth=1 movl [=11=], -36(%rax,%rcx,4) movl [=11=], -32(%rax,%rcx,4) movl [=11=], -28(%rax,%rcx,4) movl [=11=], -24(%rax,%rcx,4) movl [=11=], -20(%rax,%rcx,4) movl [=11=], -16(%rax,%rcx,4) movl [=11=], -12(%rax,%rcx,4) movl [=11=], -8(%rax,%rcx,4) movl [=11=], -4(%rax,%rcx,4) movl [=11=], (%rax,%rcx,4) addq , %rcx cmpq 9, %rcx jne .LBB0_1 xorl %eax, %eax popq %rcx retq