在 C++ 中更改越界指针的取消引用是否安全?

Is it safe to change the dereference of an out-of-bounds pointer in C++?

本文关键字:引用 取消 是否 安全 指针 C++ 越界      更新时间:2023-10-16

>假设我有一个错误的指针,我递增它以查看下一个内存位置内的内容。我的代码工作正常,没有任何错误或问题。我只是打印出这些内存位置的内容。我在屏幕上看到输出,其中一些内存位置的值为 0,其他位置包含一些大的负数或正数,这些数字似乎是按模式排列的。但是,如果我尝试更改或覆盖这些内存位置的内容怎么办?它们代表什么?这些内存位置中可能存储什么样的数据,如果更改了足够多的这些内存位置,是否有可能破坏操作系统?

#include <iostream>
using std::cout;
using std::endl;
int main() {
int num1 = 5;
int* bad_ptr = &num1;
cout << "Address of num1: " << &num1 << endl;
cout << "Dereference bad pointer: " << *bad_ptr << endl;
// The bad pointer acesses 500 memory addresses
for (int i = 0; i < 500; i++) {
bad_ptr++;
cout << "Dereference bad pointer: " << *bad_ptr << endl;
// What if I try to change it?
// *bad_ptr = 1;
}
return 0;
}

TL;DR这是未定义的行为,不应这样做。

更实际的答案是,这在很大程度上取决于地址。在此示例中,您获取的是堆栈上int的地址。如果继续递增指针,则基本上是在查看堆栈内存。如果你要用调用malloc()的指针做同样的事情,你将查看整个堆的内存。

您关于通过更改值来影响操作系统稳定性的问题,除非您在内核空间中,否则答案是否定的。但是,如果您在内核空间中运行的驱动程序中执行此操作,则可能会使操作系统崩溃。

这个答案绝对不是详尽无遗的,而且非常挥手,因为你的问题有很多细微差别,所以我推荐你去TL;一开始就瘙痒。我建议搜索和阅读基本的计算机体系结构。

引用错误的指针是未定义的。但是,您正在做的事情可能不会偶然导致错误。

在大多数C++实现中,num1 将在堆栈上分配。在大多数计算机系统中,堆栈向较低的地址增长。增加指针是将自己向上移动到调用函数的堆栈帧中(即,所有在 main 之前进行初始化的函数)。

如果你把你的循环限制做得足够大,最终你会看到一个问题。

但是,如果我尝试更改或覆盖这些内存位置的内容怎么办?它们代表什么?这些内存位置中可能存储什么样的数据,如果更改了足够多的这些内存位置,是否有可能破坏操作系统?

这都是特定于系统的,但通常,当您调用函数时,您会在堆栈上创建一个 CALL FRAME。调用帧包括函数的参数、函数调用返回后要执行的下一条指令的地址以及保存的寄存器。调用帧包括在被调用函数返回时还原调用函数所需的所有信息。

通常有一个指向当前调用帧的硬件寄存器(帧指针)。

在调用帧之间,堆栈包含当前正在执行的函数的局部变量。

当函数返回时,它使用帧指针寄存器来定位调用帧。然后还原调用帧中的数据(包括以前保存的帧指针值)并继续执行调用函数。

如果你要覆盖指针的内容,那一定是你可能要处理的。调用函数可能会看到其变量发生更改。您的程序可能会崩溃。任何事情都可能发生。

有些函数会以您的方式处理调用帧。这需要确切地知道调用帧的布局方式和寄存器的使用情况。

例如,有一个公共库函数 alloca() 类似于 malloc(),不同之处在于它在堆栈上分配内存,以便在当前函数返回时自动释放内存。实现 alloca 需要弄乱调用它的函数的状态。这需要了解调用帧的结构。

而且,如果您使用这些值,您将不会破坏操作系统。你只会伤害自己。