c++ - 未定义的行为怪癖 : reading outside a buffer causes a loop to never terminate?

标签 c++ undefined-behavior buffer-overflow

我写了一个非常简单的程序来尝试检查附加到缓冲区溢出的未定义行为。具体来说,关于当您对分配空间之外的数据执行读取时会发生什么。

#include <iostream>
#include<iomanip>

int main() {
    int values[10];
    for (int i = 0; i < 10; i++) {
        values[i] = i;
    }

    std::cout << values << " ";
    std::cout << std::endl;
    for (int i = 0; i < 11; i++) {
        //UB occurs here when values[i] is executed with i == 10
        std::cout << std::setw(2) << i << "(" << (values + i) << "): " << values[i] << std::endl;
    }
    system("pause");
    return 0;
}

当我在 Visual Studio 上运行这个程序时,结果并不令人惊讶:读取索引 10 产生垃圾:

000000000025FD70 
 0(000000000025FD70): 0
 1(000000000025FD74): 1
 2(000000000025FD78): 2
 3(000000000025FD7C): 3
 4(000000000025FD80): 4
 5(000000000025FD84): 5
 6(000000000025FD88): 6
 7(000000000025FD8C): 7
 8(000000000025FD90): 8
 9(000000000025FD94): 9
10(000000000025FD98): -1966502944
Press any key to continue . . . 

但是当我将这个程序输入 Ideone.com 的在线编译器时,I got extremely bizarre behavior:

0xff8cac48 
0(0xff8cac48): 0
1(0xff8cac4c): 1
2(0xff8cac50): 2
3(0xff8cac54): 3
4(0xff8cac58): 4
5(0xff8cac5c): 5
6(0xff8cac60): 6
7(0xff8cac64): 7
8(0xff8cac68): 8
9(0xff8cac6c): 9
10(0xff8cac70): 1
11(0xff8cac74): -7557836
12(0xff8cac78): -7557984
13(0xff8cac7c): 1435443200
14(0xff8cac80): 0
15(0xff8cac84): 0
16(0xff8cac88): 0
17(0xff8cac8c): 1434052387
18(0xff8cac90): 134515248
19(0xff8cac94): 0
20(0xff8cac98): 0
21(0xff8cac9c): 1434052387
22(0xff8caca0): 1
23(0xff8caca4): -7557836
24(0xff8caca8): -7557828
25(0xff8cacac): 1432254426
26(0xff8cacb0): 1
27(0xff8cacb4): -7557836
28(0xff8cacb8): -7557932
29(0xff8cacbc): 134520132
30(0xff8cacc0): 134513420
31(0xff8cacc4): 1435443200
32(0xff8cacc8): 0
33(0xff8caccc): 0
34(0xff8cacd0): 0
35(0xff8cacd4): 346972086
36(0xff8cacd8): -29697309
37(0xff8cacdc): 0
38(0xff8cace0): 0
39(0xff8cace4): 0
40(0xff8cace8): 1
41(0xff8cacec): 134514984
42(0xff8cacf0): 0
43(0xff8cacf4): 1432277024
44(0xff8cacf8): 1434052153
45(0xff8cacfc): 1432326144
46(0xff8cad00): 1
47(0xff8cad04): 134514984
... 
//The heck?! This just ends with a Runtime Error after like 200 lines.

很明显,使用他们的编译器,单个索引溢出缓冲区会导致程序进入无限循环!

现在,重申一下:我意识到我正在处理这里未定义的行为。但尽管如此,我还是想知道幕后究竟发生了什么导致了这一切。物理上执行缓冲区溢出的代码仍在执行 4 个字节的读取并将读取的任何内容写入(可能受到更好保护的)缓冲区。导致这些问题的编译器/CPU 正在做什么?

最佳答案

导致条件i < 11的执行路径有两条正在评估中。

第一个是在初始循环迭代之前。自 i已初始化为 0就在检查之前,这是微不足道的事实。

第二个是在成功的循环迭代之后。由于循环迭代导致values[i]被访问,和values只有 10 个元素,只有 i < 10 才有效.如果i < 10 , 在 i++ 之后, i < 11也必须为真。

这是 Ideone 的编译器 (GCC) 正在检测的内容。条件没办法i < 11除非你有一个无效的程序,否则它可能永远是错误的,因此它可以被优化掉。同时,您的编译器不会特意检查您是否有无效程序,除非您提供额外的选项告诉它这样做(例如 GCC/clang 中的 -fsanitize=undefined)。

这是实现必须做出的权衡。他们可以支持无效程序的可理解行为,或者他们可以支持有效程序的原始速度。或者两者兼而有之。 GCC 肯定非常关注后者,至少在默认情况下是这样。

关于c++ - 未定义的行为怪癖 : reading outside a buffer causes a loop to never terminate?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41902356/

相关文章:

c++ - 删除复制构造函数的类仍然可以复制吗?

C++ 文本文件读取

c - 为什么 C 数组的 5[a] 不会超出范围?

c++ - 迭代器和标量对象之间的未定义行为有什么区别吗?

c - 缓冲区溢出困境

c++ - boost asio 绑定(bind)端点

c++ - key = pair 的多重映射

c++ - 类 union 类中 `reinterpret_cast` 上的 `this` 是未定义的行为吗?

operating-system - 堆栈溢出和缓冲区溢出有什么区别?

security - 什么是练习缓冲区溢出的好程序(仅用于教育目的)?