a.c
with following content as a memory leak MRE:#include <stdlib.h>
void Foo() { malloc(1); }
int main() { Foo(); return 0;}
$ clang++ -g -fsanitize=address a.c; ./a.out
=================================================================
==...==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 1 byte(s) in 1 object(s) allocated from:
#0 0x... in malloc (/.../a.out+0xa114e) (BuildId: ...)
#1 0x... in Baz() (/.../a.c:2:14
#2 0x... in main (/.../a.c:3:14
#3 0x... in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
SUMMARY: AddressSanitizer: 1 byte(s) leaked in 1 allocation(s).
To get a reasonable performance add
-O1
or higher.
-O1
has been added):$ clang++ -O1 -g -fsanitize=address a.c; ./a.out
Can memory leak still be detected by Clang LeakSanitizer when code optimization level 1 or higher is used?
If the answer is yes, please provide a minimal reproducible example (MRE) proving it.
If the answer is no, please explain why (link to Clang compiler source code, ...).
Clang LeakSanitizer documentation Usage section does not explicitly mention that code optimization shall not be used.
Above observations were made with version 18 of Clang, installed on Linux Ubuntu 22.04.3 using LLVM automatic installation script.
As explained by user17732522 in a comment, the a.c
file example in the Background section does not lead to memory leak detection when the -O1
option is used because:
The optimized program won't have any actual memory leak. The malloc call will be optimized away since it doesn't affect observable behavior
Your minimal example is too minimal -- clang
was able to optimize everything away from it:
(gdb) disas main
Dump of assembler code for function main:
0x0000000000401120 <+0>: xor %eax,%eax
0x0000000000401122 <+2>: ret
As you can see, none of Foo
or malloc
remain.
To make it a bit more realistic, try this:
#include <stdlib.h>
#include <stdio.h>
void* Foo() { return malloc(1); }
void Bar(void *p) { printf("p = %p\n", p); }
int main() { Bar(Foo()); return 0;}
clang -g -O0 -fsanitize=address a1.c && ./a.out
p = 0x502000000010
=================================================================
==191==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 1 byte(s) in 1 object(s) allocated from:
#0 0x4c8822 in malloc (/tmp/a.out+0x4c8822) (BuildId: a27851507d14179bca1fa40aa114a3e5ffa99c23)
#1 0x50644d in Foo /tmp/a1.c:4:22
#2 0x506493 in main /tmp/a1.c:6:18
#3 0x7f9a74195149 in __libc_start_call_main (/lib64/libc.so.6+0x28149) (BuildId: 7ea8d85df0e89b90c63ac7ed2b3578b2e7728756)
#4 0x7f9a7419520a in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x2820a) (BuildId: 7ea8d85df0e89b90c63ac7ed2b3578b2e7728756)
#5 0x42a324 in _start (/tmp/a.out+0x42a324) (BuildId: a27851507d14179bca1fa40aa114a3e5ffa99c23)
SUMMARY: AddressSanitizer: 1 byte(s) leaked in 1 allocation(s).
And now with -O1
:
clang -g -O1 -fsanitize=address a1.c && ./a.out
p = 0x502000000010
=================================================================
==197==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 1 byte(s) in 1 object(s) allocated from:
#0 0x4c8822 in malloc (/tmp/a.out+0x4c8822) (BuildId: 1ffaa6630367e5a8f0a95663181cd0d01efdc513)
#1 0x50646a in Foo /tmp/a1.c:4:22
#2 0x50646a in main /tmp/a1.c:6:18
#3 0x7f804f1c020a in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x2820a) (BuildId: 7ea8d85df0e89b90c63ac7ed2b3578b2e7728756)
#4 0x42a324 in _start (/tmp/a.out+0x42a324) (BuildId: 1ffaa6630367e5a8f0a95663181cd0d01efdc513)
SUMMARY: AddressSanitizer: 1 byte(s) leaked in 1 allocation(s).