0

考虑这个简单的程序:

#include <array>
#include <iostream>
#include <cstdlib>

int main(int argc, char* argv[]) {
    std::array<int, 5> arr = {0, 1, 2, 3, 4};
    int idx = std::atoi(argv[1]);
    int val = std::atoi(argv[2]);

    arr[idx] = val;
    for (auto i=0u; i <= idx; i++) {
        std::cout << "arr[" << i << "] = " << arr[i] << std::endl;
    }
}

如果我像这样编译并将其与 GCC 6.3.1 链接:

g++ -O0 -std=gnu++14 -fsanitize=undefined example.cpp

并像这样运行它:

a.out 5 98

我没有收到任何警告,即使我正在写入和读取 'arr' 末尾之后的一个元素(数组在索引 4 处结束)。

如果我运行:

a.out 6 98

我收到一条警告,提示“索引 6 超出类型“int [5]”的范围。在这种情况下,我正在编写和读取 'arr' 末尾之后的两个元素。

为什么非一个案例不会引发错误?我猜是因为数组末尾的一个元素是有效的内存地址(即迭代器可以指向它?)。您能否推荐任何其他可以可靠地检测到一个元素的越界访问的工具?

编辑

我也可以运行:

g++ -O0 -std=gnu++14 -fsanitize=bounds-strict example.cpp

而且我看到了相同的行为,即一个元素的越界访问不会触发警告,但是,两个元素的越界访问会触发。这是我试图理解的部分。

4

2 回答 2

4

为什么非一个案例不会引发错误?

因为-fsanitize=undefined没有检测到越界访问。

您能否推荐任何其他可以可靠地检测到一个元素的越界访问的工具?

我建议gcc使用-fsanitize=address.

$ g++ -O0 -std=gnu++14 -fsanitize=address 1.cpp
$ ./a.out  6 98
=================================================================
==119887==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd3b1aa4b8 at pc 0x560be273c4e9 bp 0x7ffd3b1aa450 sp 0x7ffd3b1aa440
WRITE of size 4 at 0x7ffd3b1aa4b8 thread T0
    #0 0x560be273c4e8 in main (/tmp/a.out+0x14e8)
    #1 0x7f9dafafe001 in __libc_start_main (/usr/lib/libc.so.6+0x27001)
    #2 0x560be273c17d in _start (/tmp/a.out+0x117d)
...

这些选项记录在gcc 仪器选项中。

旁注:在我的一个项目中,我使用-fsanitize=address -fsanitize=undefined -fsanitize=leak -fsanitize=pointer-subtract -fsanitize=pointer-compare -fno-omit-frame-pointer -fstack-protector-all -fstack-clash-protection -fcf-protection.

于 2020-05-24T11:42:24.883 回答
0

如果你想要边界检查使用array::at

std::array<T,N>::at:

#include <array>
#include <iostream>
#include <cstdlib>

int main(int argc, char* argv[]) 
{
    std::array<int, 5> arr = {0, 1, 2, 3, 4};
    int idx = std::atoi(argv[1]);
    int val = std::atoi(argv[2]);

    try
    {
       arr.at(idx) = val; 
    }
    catch(std::out_of_range var)
    {
        std::cout<<"Out of bounds"<<std::endl;
    }

    for (auto i=0u; i <= idx; i++) 
    {
        try
        {
            std::cout << "arr[" << i << "] = " << arr.at(i) << std::endl;
        }
        catch(std::out_of_range var)
        {
            std::cout<<"Out of bounds"<<std::endl;
        }
    }
}

输出:

Out of bounds                                                                                                                 
arr[0] = 0                                                                                                                    
arr[1] = 1                                                                                                                    
arr[2] = 2                                                                                                                    
arr[3] = 3                                                                                                                    
arr[4] = 4 
Out of bounds 
于 2020-05-24T11:39:24.747 回答