在最近的一个项目中,我测试了不同编译器标志和消毒剂的组合,以评估调试我的 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
- 铿锵声13.0.0-2
- glibc 2.33-5
但是,我刚刚测试并验证了示例和观察结果也适用于gcc:bullseye
来自 docker-hub 的 linux/amd64 的 docker 映像。