我已经被咬了好几次了,因为我会写入超出范围的数组。我已经在一个特定的固件上工作了 2 年多,并怀疑存在溢出,但现在几乎不可能找到 - 例如:
uint8_t example[50];
uint8_t example2[100];
for(uint8_t i = 0; i < sizeof(example2); i++)
example[i] = i;
我知道上面的代码示例很原始。这只是我试图描述的一个例子。
是否有可用的软件包或函数可以检测这些“泄漏”?
带有标志
-Wall
的最新版本的 GCC 将检测简单的错误,例如示例中的问题,并打印警告。
Valgrind 工具更先进,但正确配置和使用也需要更多工作。
宇宙中没有任何工具可以检测出所有可能的错误,所以从最容易使用的开始。
工具 Frama-c 通过 Eva 插件,允许进行值分析:它能够计算每个变量的每个可能值,然后检测(以及其他问题)数组溢出,即使在不平凡的代码源中也是如此。
GCC 会警告此类越界问题。使用
-Wall -pedantic -O1
编译此代码示例:
int main(void) {
int example[50];
for (int i = 0; i < 100; i++)
example[i] = i;
return example[0];
}
...导致此编译警告(使用 ARM GCC 11.2 (linux),可在 Godbolt 上进行测试,就像 Tom V 的答案的评论中已经指出的那样):
<source>: In function 'main':
<source>:4:20: warning: iteration 50 invokes undefined behavior [-Waggressive-loop-optimizations]
4 | example[i] = i;
| ~~~~~~~~~~~^~~
<source>:3:23: note: within this loop
3 | for (int i = 0; i < 100; i++)
| ~~^~~~~
Compiler returned: 0
在这种情况下,需要优化选项标志
-O1
(或 -O2
、-Os
)才能从 GCC 获取未定义行为警告。 -O3
优化了循环输出,所以不会有警告。没有优化(默认选项-O0
)也不会导致任何警告,因为据我所知,GCC 显然只在优化循环时才注意到越界问题(参见-Waggressive-loop-optimizations
)。
(一些注意事项: GCC 的
-fstack-check
和 -fstack-protector
选项也可能值得一看(运行时检查)。 Valgrind 或其他静态/动态分析工具也很有用。然而,在微控制器上,在目标上运行时分析程序通常并不那么容易,模拟器或在开发机器上使用不同的编译器编译程序的非特定于平台的部分也可以有所帮助,使其更容易僵硬。
相关主题已在此讨论:访问数组越界不会出错,为什么?、gcc 选项 -fstack-check 到底如何工作?)