Reputation: 43
When I use Address Sanitizer(clang v3.4) to detect memory leak, I found that using -O(except -O0) option would always lead to a no-leak-detected result.
The code is simple:
#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;
}
when compile with -O0,
clang -fsanitize=address -g -O0 main.cpp
it will detect memory correctly,
==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).
however, when -O added,
clang -fsanitize=address -g -O main.cpp
nothing is detected! And I find nothing about it in official document.
Upvotes: 4
Views: 6514
Reputation: 1
Look into the generated code.
Both GCC & Clang actually know about the semantics of malloc
. Because on my Linux/Debian system <stdlib.h>
contains
extern void *malloc (size_t __size) __THROW __attribute_malloc__ __wur;
and the __attribute_malloc__
& _wur
(and __THROW
) are macros defined elsewhere. Read about Common Function Attributes in GCC documentation, and Clang documentation says:
Clang aims to support a broad range of GCC extensions.
I strongly suspect that with -O
the call to malloc
is optimized by removing it.
On my Linux/x86-64 machine using clang -O -S psbshdk.c
(with clang 3.8) I am indeed getting:
.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
The address sanitizer is working on the emitted binary (which won't contain any malloc
call).
BTW, you could compile with clang -O -g
then use valgrind, or compile with clang -O -fsanitize=address -g
. Both clang
& gcc
are able to optimize and give some debug information (which might be "approximate" when optimizing a lot).
Upvotes: 4
Reputation: 93274
This is because your code is completely optimized away. The resulting assembly is something like:
main: # @main
xorl %eax, %eax
retq
Without any call to malloc
, there is no memory allocation... and therefore no memory leak.
In order to to have AddressSanitizer detect the memory leak, you can either:
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
Upvotes: 7