为啥`-fno-omit-frame-pointer` 会干扰 ASAN?
Posted
技术标签:
【中文标题】为啥`-fno-omit-frame-pointer` 会干扰 ASAN?【英文标题】:Why does `-fno-omit-frame-pointer` interfere with ASAN?为什么`-fno-omit-frame-pointer` 会干扰 ASAN? 【发布时间】:2022-01-05 15:13:40 【问题描述】:在最近的一个项目中,我测试了不同编译器标志和消毒剂的组合,以评估调试我的 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
观察
我使用了编译器和链接器标志的不同组合,有时我观察到地址清理程序报告了 memleak,而在其他情况下它没有报告 memleak。我已经消除了所有潜在的编译器标志,直到找到影响 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 clang 13.0.0-2 glibc 2.33-5但是,我刚刚测试并验证了示例和观察结果也适用于来自 docker-hub 的 linux/amd64 的 docker 映像 gcc:bullseye
。
【问题讨论】:
SO 上已经有很多问题解释什么是帧指针以及省略它(或不省略)意味着什么。参见例如***.com/questions/10057443/…、***.com/questions/14666665/…、***.com/questions/1395591/…、***.com/questions/579262/… 因此省略帧指针是一种常见的优化,您是在告诉编译器不要使用该优化。目前尚不清楚您为什么要避免它,但无论哪种方式,它都没有充分的理由影响消毒剂,因此这可能是编译器/消毒剂错误。它会影响两个编译器也就不足为奇了,因为 AFAIK 它们共享许多相同的清理代码。 我认为消毒剂最初来自 clang。所以我要说的是,当您同时使用消毒剂和-fomit-frame-pointer
时,clang 似乎出现了一个错误。 (我不知道原始错误是如何产生的。)但 GCC 可能继承了相同的错误,因为它们的清理程序代码是从 clang 移植的。
@NateEldredge 与 [AMT]san 不同,LeakSanitizer 是一个仅限库的解决方案,因此它不依赖于编译器。
【参考方案1】:
这是 LeakSanitizer 的一个已知问题:参见例如#1233、#937 或 #699。核心原因是 Lsan 是一个比 Asan 简单得多的工具,并且不保证检测到泄漏。此外,它检测特定泄漏的能力取决于堆栈帧的布局,堆栈帧的布局可能会因不相关的因素(例如在您的情况下添加帧指针)而有所不同。
不幸的是,这个问题没有可靠的解决方案 - 只需在尽可能多的编译器(gcc、clang)和/或平台(x86、ARM、android 等)上自动测试您的应用程序,其中一些会捕获大概率泄漏。
【讨论】:
好的,谢谢你的参考。以上是关于为啥`-fno-omit-frame-pointer` 会干扰 ASAN?的主要内容,如果未能解决你的问题,请参考以下文章
是否有任何分析器可以在 x86_64 上与 -fomit-frame-pointer 一起使用?
为啥使用 glTranslatef?为啥不直接更改渲染坐标?