g++是否可以启用数组边界检查?

19

是否有可能让g++在使用某个标志编译以下文件时显示错误?

#include <iostream>
using namespace std;

int main()
{
   int arr[ 2 ];

   cout << arr[ 4 ] << endl;

   return 0;
}

我看到一些像 gcc -Wall -O2 main.c 这样的东西,它只适用于C语言,而不适用于C++。


1
这个程序加上了-Wall -Wextra -ansi -pedantic选项,但是没有产生任何警告 :( - EnabrenTane
5个回答

8

5
您可以使用静态分析器,例如Cppcheck。当对您上面的代码运行时:
$ cppcheck --enable=all test.cpp
Checking test.cpp...
[test.cpp:6]: (style) 变量 'arr' 没有被赋值
[test.cpp:8]: (error) 数组 'arr[2]' 的索引 4 超出范围
您可以将Cppcheck集成到您的构建过程中,并仅在Cppcheck通过时才考虑您的代码已成功构建。

3
对于原始数组,我认为不行,因为在您的示例和MingW g ++ 4.4.1中, -fbounds-check 无法正常工作,并且因为我拥有的旧版3.x文档说:

-fbounds-check

对于支持它的前端, 生成额外的代码以检查 用于访问数组的索引是否 在声明的范围内。这是 目前仅由Java和Fortran 77前端支持, 其中此选项默认为true和false 分别。

但是,使用 std :: vector ,您可以使用 at 进行略微不切实际的运行时边界检查(生成异常)。并且您可以使用标准库的特殊调试版本,该版本提供 [] 的实用运行时边界检查。例如,在编译时...
#include <iostream>
#include <vector>
using namespace std;

int main()
{
   vector<int>  arr( 2 );

   cout << arr[ 4 ] << endl;
}

在g++标准库的实现中,对于发布版本和调试版本,您会分别获得不同的无检查和检查行为:

C:\test> g++ x.cpp & a
4083049
C:\test> g++ x.cpp -D _GLIBCXX_DEBUG -D _GLIBCXX_DEBUG_PEDANTIC & a c:\program files\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/debug/vector:265: error: attempt to subscript container with out-of-bounds index 4, but container only holds 2 elements.
参与操作的对象: 序列 "this" @ 0x0x22ff1c { type = NSt7__debug6vectorIiSaIiEEE; }
应用程序以不正常的方式请求运行时终止它。 有关更多信息,请联系应用程序的支持团队。
C:\test> _

据报道,在新版g++(4.0之后)中,您不需要使用_GLIBCXX_DEBUG_PEDANTIC符号。有关详细信息,请参见GNU文档

祝好!


2
{boost,std::tr1,std}::array 也有 at 方法。 - James McNellis
-fbounds-check似乎只在开启优化时起作用。因此,我期望-O -fbounds-check可以工作,但在OP的示例中却没有,就像你说的那样。然而,-fsanitize=address,undefined确实可以捕获它:https://godbolt.org/z/5MPx3d668 - Jerry Jeremiah

2

我记得从ffmpeg或x264中看到过gcc或g++的警告信息,大致是这样的:

"警告:数组索引可能超出范围"

http://gcc.gnu.org/ml/gcc/2000-07/msg01000.html

看起来它可能已经被包含进去了。

限制在于你有一个像上面那样的例子。一旦你使用变量而不是字面值,就不可能了。除非是在一个简单的循环中。


根据维基百科(https://en.wikipedia.org/wiki/AddressSanitizer)的说法,ffmpeg使用AddressSanitizer。以下可能是它的输出结果。关于AddressSanitizer的更多信息,请参见另一个问题的答案(//stackoverflow.com/a/17637383/2157640)。 - Palec

0

您可以使用std::vector替换数组。向量具有访问器成员函数({{link1:std::vector::at}}),该函数在运行时执行边界检查。

对于缓冲区溢出的编译时检查是一个非常困难的不可判定问题。不幸的是,通常需要使用完整的静态分析工具来处理它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接