你试过-fmudflap
GCC 吗?这些是运行时检查,但很有用,因为无论如何您通常都必须处理运行时计算的索引。它不会默默地继续工作,而是会通知您这些错误。
-fmudflap -fmudflapth -fmudflapir
对于支持它的前端(C 和 C++),检测所有有风险的指针/数组解引用操作、一些标准库字符串/堆函数,以及其他一些具有范围/有效性测试的相关结构。如此检测的模块应该不受缓冲区溢出、无效堆使用和其他一些 C/C++ 编程错误的影响。该工具依赖于一个单独的运行时库 (libmudflap),如果在链接时给出 -fmudflap,它将被链接到一个程序中。检测程序的运行时行为由 MUDFLAP_OPTIONS 环境变量控制。有关其选项,请参见“env MUDFLAP_OPTIONS=-help a.out”。
如果您的程序是多线程的,请使用 -fmudflapth 而不是 -fmudflap 来编译和链接。如果检测应忽略指针读取,则使用 -fmudflapir 和 -fmudflap 或 -fmudflapth。这产生了更少的检测(因此更快的执行),并且仍然提供了一些保护以防止直接破坏内存的写入,但允许错误读取的数据在程序中传播。
以下是泥瓣给我的例子:
[js@HOST2 cpp]$ gcc -fstack-protector-all -fmudflap -lmudflap mudf.c
[js@HOST2 cpp]$ ./a.out
*******
mudflap violation 1 (check/write): time=1229801723.191441 ptr=0xbfdd9c04 size=56
pc=0xb7fb126d location=`mudf.c:4:3 (main)'
/usr/lib/libmudflap.so.0(__mf_check+0x3d) [0xb7fb126d]
./a.out(main+0xb9) [0x804887d]
/usr/lib/libmudflap.so.0(__wrap_main+0x4f) [0xb7fb0a5f]
Nearby object 1: checked region begins 0B into and ends 16B after
mudflap object 0x8509cd8: name=`mudf.c:3:7 (main) a'
bounds=[0xbfdd9c04,0xbfdd9c2b] size=40 area=stack check=0r/3w liveness=3
alloc time=1229801723.191433 pc=0xb7fb09fd
number of nearby objects: 1
[js@HOST2 cpp]$
它有很多选择。例如,它可以在违规时分叉 gdb 进程,可以向您显示程序泄漏的位置(使用-print-leaks
)或检测未初始化的变量读取。用于MUDFLAP_OPTIONS=-help ./a.out
获取选项列表。由于 mudflap 只输出地址而不是文件名和源代码行,所以我写了一个小 gawk 脚本:
/^ / {
file = gensub(/([^(]*).*/, "\\1", 1);
addr = gensub(/.*\[([x[:xdigit:]]*)\]$/, "\\1", 1);
if(file && addr) {
cmd = "addr2line -e " file " " addr
cmd | getline laddr
print $0 " (" laddr ")"
close (cmd)
next;
}
}
1 # print all other lines
将 mudflap 的输出通过管道传输到其中,它将显示每个回溯条目的源文件和行。
还有-fstack-protector[-all]
:
-fstack-protector
发出额外的代码来检查缓冲区溢出,例如堆栈粉碎攻击。这是通过将保护变量添加到具有易受攻击对象的函数来完成的。这包括调用 alloca 的函数,以及缓冲区大于 8 字节的函数。进入函数时初始化守卫,然后在函数退出时检查。如果保护检查失败,则会打印一条错误消息并退出程序。
-fstack-protector-all
与 -fstack-protector 类似,只是所有函数都受到保护。