提问人:Emanuel Schmidt 提问时间:11/28/2021 最后编辑:Emanuel Schmidt 更新时间:11/30/2021 访问量:1102
为什么“-fno-omit-frame-pointer”会干扰 ASAN?
Why does `-fno-omit-frame-pointer` interfere with ASAN?
问:
在最近的一个项目中,我测试了不同编译器标志和清理程序的组合,以评估调试 C 代码的相关性。通过测试这些组合的影响,我偶然发现了一种我不理解的行为。
再生产者
我使用一个包含内存泄漏的小型 hello-world 代码示例来触发地址清理程序 (ASAN):
#include<stdlib.h>
#include<stdio.h>
int main () {
int * memleak = calloc(1, sizeof(int)); // no free -> leaked memory
printf ("A memleaked memory: %d\n", *memleak);
printf ("Hello World\n"); // Note: I found that if I comment out this function, ASAN will also report again
}
观察
我使用了编译器和链接器标志的不同组合,有时我观察到地址清理程序报告了内存泄漏,而在其他情况下它没有报告内存泄漏。我已经消除了所有潜在的编译器标志,直到我找到一组影响 ASAN 报告或忽略内存泄漏的最小标志:
使用命令编译时,ASAN 将报告内存泄漏
cc -fsanitize=address -fno-omit-frame-pointer -Og -o main.c.o -c ./main.c && cc -o hello main.c.o -fsanitize=address,undefined && ./hello # returns 1
cc -fsanitize=address,undefined -Og -o main.c.o -c ./main.c && cc -o hello main.c.o -fsanitize=address,undefined && ./hello # returns 1
cc -fsanitize=address,undefined -fno-omit-frame-pointer -o main.c.o -c ./main.c && cc -o hello main.c.o -fsanitize=address,undefined && ./hello # returns 1
使用命令编译时,ASAN 不会报告内存泄漏
cc -fsanitize=address,undefined -fno-omit-frame-pointer -Og -o main.c.o -c ./main.c && cc -o hello main.c.o -fsanitize=address,undefined && ./hello # returns 0
然而
我观察到相同的行为,与使用 GCC 或 clang 无关。因此,我担心这不是一个错误,是由不同消毒剂、优化级别和标志之间的意外干扰引起的,而是我无法理解的预期行为,因为我缺乏了解的影响是什么。-fno-omit-frame-pointer
-fno-omit-frame-pointer
如果有人能总结一下它的作用/作用以及在哪些情况下起作用,或者解释这个标志对给定示例的影响,或者指出我找到这些信息的地方,我将不胜感激。-fno-omit-frame-pointer
-fomit-frame-pointer
为了完整性
我正在 Arch-linux 上工作,并运行了以下版本的软件:
- GCC 11.1.0-1
- 叮叮当当 13.0.0-2
- 格利布克 2.33-5
但是,我刚刚测试并验证了示例和观察结果也适用于 docker-hub 的 linux/amd64 的 docker 映像。gcc:bullseye
答:
这是 LeakSanitizer 的已知问题:例如参见 #1233、#937 或 #699。核心原因是 Lsan 是一个比 Asan 简单得多的工具,并且不能保证检测到泄漏。此外,它检测特定泄漏的能力取决于堆栈帧的布局,这些布局可能会因不相关的因素而有所不同(例如在您的情况下添加帧指针)。
不幸的是,这个问题没有可靠的解决方案 - 只需在尽可能多的编译器(gcc、clang)和/或平台(x86、ARM、Android 等)上自动测试您的应用程序,其中一些很可能会发现泄漏。
评论
-fomit-frame-pointer