Ada*_*eld 20 c arrays warnings
最近,我的一位同事通过写出堆栈上的静态数组(他在不增加数组大小的情况下添加了一个元素)来严重受伤.编译器不应该捕获这种错误吗?以下代码使用gcc完全编译,即使使用-Wall -Wextra选项,但它显然是错误的:
int main(void)
{
int a[10];
a[13] = 3; // oops, overwrote the return address
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我很肯定这是不确定的行为,虽然我现在找不到C99标准的摘录.但是在最简单的情况下,数组的大小称为编译时,并且索引在编译时是已知的,编译器是否应该至少发出警告?
der*_*ert 27
GCC 并警告这一点.但是你需要做两件事:
a是,并且你跑掉了边缘..
$ cat foo.c
int main(void)
{
int a[10];
a[13] = 3; // oops, overwrote the return address
return a[1];
}
$ gcc -Wall -Wextra -O2 -c foo.c
foo.c: In function ‘main’:
foo.c:4: warning: array subscript is above array bounds
Run Code Online (Sandbox Code Playgroud)
顺便说一句:如果你在测试程序中返回[13],那也不会有效,因为GCC再次优化了数组.
Joh*_*itb 10
你有没有尝试-fmudflap过GCC?这些是运行时检查,但很有用,因为大多数情况下,您仍然需要处理运行时计算的索引.它将不会默默地继续工作,而是会通知您有关这些错误的信息.
-fmudflap -fmudflapth -fmudflapir对于支持它的前端(C和C++),检测所有有风险的指针/数组解除引用操作,一些标准库字符串/堆函数,以及一些其他具有范围/有效性测试的相关构造.如此检测的模块应该不受缓冲区溢出,无效堆使用以及一些其他类C/C++编程错误的影响.该指令依赖于一个单独的运行时库(libmudflap),如果在链接时给出-fmudflap,它将链接到一个程序中.已检测程序的运行时行为由MUDFLAP_OPTIONS环境变量控制.有关其选项,请参阅"env MUDFLAP_OPTIONS = -help a.out".如果您的程序是多线程的,请使用-fmudflapth而不是-fmudflap进行编译和链接.除-fmudflap或-fmudflapth外,如果检测应忽略指针读取,请使用-fmudflapir.这样可以减少检测(因此执行速度更快),并且仍可以防止直接内存损坏写入,但允许错误地读取数据在程序中传播.
以下是mudflap为您提供的示例:
[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]$
Run Code Online (Sandbox Code Playgroud)
它有很多选择.例如,它可以在违规时分叉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
Run Code Online (Sandbox Code Playgroud)
将mudflap的输出传递到其中,它将显示每个回溯条目的源文件和行.
另外-fstack-protector[-all]:
-fstack-protector发出额外的代码来检查缓冲区溢出,例如堆栈粉碎攻击.这是通过向具有易受攻击对象的函数添加保护变量来完成的.这包括调用alloca的函数,以及大于8字节的缓冲区的函数.输入功能时会初始化防护装置,然后在功能退出时进行检查.如果防护检查失败,则会打印错误消息并退出程序.
-fstack-protector-all与-fstack-protector类似,但所有功能都受到保护.
它不是静态数组.
是否未定义行为,它从数组的开头写入地址13个整数.你有什么责任呢?由于合理的原因,有几种C技术故意错误分配数组.在不完整的编译单元中,这种情况并不罕见.
根据您的标志设置,此程序的许多功能将被标记,例如从不使用该数组的事实.并且编译器可能很容易优化它而不是告诉你 - 一棵树落在森林里.
这是C方式.这是你的阵列,你的记忆,用它做你想做的事.:)
(有许多lint工具可以帮助你找到这类东西;你应该自由地使用它们.虽然它们并不都是通过编译器完成的;编译和链接通常很乏味.)
| 归档时间: |
|
| 查看次数: |
7904 次 |
| 最近记录: |