使用优化代码进行 Clang LeakSanitizer 内存泄漏检测

问题描述 投票:0回答:1

1.背景

  • 让我们将具有以下内容的 C 文件
    a.c
    视为内存泄漏 MRE:
#include <stdlib.h>
void Foo() { malloc(1); }
int main() { Foo();  return 0;}
  • 一方面,正如预期的那样,如果运行以下命令,Clang LeakSanitizer(集成到 Clang AddresSanitizer)会检测到内存泄漏:
$ 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).
  • 另一方面,Clang AddressSanitizer 文档 Usage 部分提到:

要获得合理的性能,请添加

-O1
或更高。

2.关注

    如果运行以下命令,
  • Clang LeakSanitizer 不会检测内存泄漏(已添加代码生成选项
    -O1
    ):
$ clang++ -O1 -g -fsanitize=address a.c; ./a.out

3.问题

使用代码优化级别 1 或更高级别时,Clang LeakSanitizer 仍然可以检测到内存泄漏吗?

  • 如果答案是,请提供一个最小的可重现示例(MRE)来证明这一点。

  • 如果答案是,请解释为什么(链接到 Clang 编译器源代码,...)。

4.备注

  • Clang LeakSanitizer文档Usage部分没有明确提到不应使用代码优化。

  • 以上观察结果是使用 18 版 Clang 进行的,使用 LLVM 自动安装脚本安装在 Linux Ubuntu 22.04.3 上。

  • 正如 user17732522 在 comment 中所解释的,当使用

    a.c
    选项时,背景部分中的
    -O1
    文件示例不会导致内存泄漏检测,因为:

优化后的程序不会有任何实际的内存泄漏。 malloc 调用将被优化,因为它不会影响可观察的行为

c memory-leaks clang address-sanitizer leak-sanitizer
1个回答
0
投票

你的最小示例是太小了——

clang
能够优化一切远离它:

(gdb) disas main
Dump of assembler code for function main:
   0x0000000000401120 <+0>:     xor    %eax,%eax
   0x0000000000401122 <+2>:     ret

如您所见,

Foo
malloc
都没有保留。

为了让它更真实一点,试试这个:

#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).

现在与

-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).
© www.soinside.com 2019 - 2024. All rights reserved.