这些所谓的“灾难”到底是什么?指针使用不当会导致什么?

发布于 2024-10-09 01:56:25 字数 270 浏览 7 评论 0原文

我在程序中越来越多地使用指针,在阅读有关指针的内容时,我发现的每一个指南或教程都说,不正确地使用指针可能会产生“灾难性”结果。

现在,我遇到过一些大内存泄漏的情况,以及指针取消引用错误的指针变量,返回错误的值,但除此之外没有发生任何“灾难性”的情况;就像我的电脑和/或其他程序崩溃一样。

有人可以给我一个简单的代码示例,它肯定会产生“灾难性”的结果,也许还有一些发生的事情的背景故事,以防万一您不小心使用了那段代码?我所说的“灾难性”结果是指可能干扰其他程序或操作系统并可能导致它们崩溃的代码。

I've been using pointers more and more in my programs, and while reading up about pointers, every single guide or tutorial I found said that incorrect use of pointers could yield 'disastrous' results.

Now, I've had a few cases of some big memory leaks, and pointers dereferencing a wrong pointer variable, returning an incorrect value, but other than that nothing 'disastrous' has ever occurred; like my computer and/or other programs crashing.

Can someone give me a simple code example that will definitely yield 'disastrous' results, perhaps with some back-story of what happened, in case you've ever accidentally used that piece of code? By 'disastrous' results, I mean code that might interfere with other programs or the OS, and possibly make them crash.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

秋日私语 2024-10-16 01:56:25

不正确的指针运算也可能导致灾难,因为边界错误会导致缓冲区溢出,而缓冲区溢出会导致数据损坏,例如堆栈崩溃:

void test_fun(int i)
    int x[5];
    for (int *p = x; p < x+10; ++p) { // obvious error, some are more subtle
        *p = i;
    }
    return; // execution may resume at address `i`, with entertaining results
}

当然,仅调用 strcpymemcpy[*],您不必自己进行指针算术。如果攻击者控制了 i 的值(可能是因为它是从输入文件读取的,并且攻击者制作了恶意文件),那么您可能会遇到比崩溃更糟糕的情况。结合更多特定于平台的技巧,攻击者可能能够安排返回 i 最终执行攻击者提供的代码。

[*] 或 strncpystrlcpystrcpy_sstd::copy,在任何人开始之前。一旦你以某种方式得到了错误的边界,那么向边界检查函数提供错误的边界仍然是错误的......

Incorrect pointer arithmetic can lead to disasters too, because getting the bounds wrong leads to buffer overflows, and buffer overflows lead to corrupted data, for example stack smashing:

void test_fun(int i)
    int x[5];
    for (int *p = x; p < x+10; ++p) { // obvious error, some are more subtle
        *p = i;
    }
    return; // execution may resume at address `i`, with entertaining results
}

Of course, you can make the same mistake just calling strcpy or memcpy[*], you don't have to be doing the pointer arithmetic yourself. If an attacker controls the value of i (perhaps because it's read from an input file, and the attacker crafts a malicious file), then you could have worse than a crash on your hands. In combination with more platform-specific tricks, the attacker might be able to arrange that returning to i eventually ends up executing code supplied by the attacker.

[*] or strncpy, or strlcpy, or strcpy_s, or std::copy, before anyone starts. Once you've got a bound wrong somehow, then supplying that wrong bound to a bounds-checking function is still wrong...

留一抹残留的笑 2024-10-16 01:56:25

有两种主要的灾难——悬空指针和内存泄漏。

悬空指针是指指针存储的地址不是对象的地址:

T* first;
T* second; //somewhere in another piece of code
first = new T();
second = first;
delete first;
first = 0; //second still stores the address of an already deleted object

内存泄漏是指没有指针存储堆分配对象的地址:

T* object;
for( int i = 0; i < 10; i++ ) {
  object = new T();
}
delete object; // now the first nine objects are unreacheable

悬空指针不好,因为使用它们会导致未定义的行为 -程序可能会崩溃或修改一些不相关的数据,这将导致以后出现问题。内存泄漏很糟糕,因为分配的内存无法重用,因此程序一段时间后可能会出现内存不足的情况。

There're two main kinds of disasters - dangling pointers and memory leaks.

Dangling pointer is when a pointer stores an address that is not an address of an object:

T* first;
T* second; //somewhere in another piece of code
first = new T();
second = first;
delete first;
first = 0; //second still stores the address of an already deleted object

memory leak is when there're no pointers storing an address of a heap-allocated object:

T* object;
for( int i = 0; i < 10; i++ ) {
  object = new T();
}
delete object; // now the first nine objects are unreacheable

Dangling pointers are bad because using them you leads to undefined behavior - program might crash or modify some unrelated data and this will cause problems later. Memory leaks are bad because allocated memory can't be reused and so the program can get short on memory some time later.

小清晰的声音 2024-10-16 01:56:25

我想到了一些情况:

  • 在离开作用域后继续访问 free()/delete()d 内存或局部变量
  • 由于所有权不明确而导致堆内存
  • 泄漏 对数据的意外共享访问,其中对指向值的更改可能会造成混淆一些针对它们的算法
    • 意外的浅拷贝
  • 由于对实际包含指向其他数据的指针的假定 POD 数据进行简单的二进制写入而造成的不完整/有缺陷的序列化
  • 共享内存中的多进程不安全数据,其中指针(尤其是虚拟分派指针)需要在不同的内存中有所不同访问它的不同进程
  • 循环数据链接,导致代码陷入循环中无限期地
  • 在数据中移动指针,从而意外地移动到数据之外(问题类似于数组索引,但更复杂,因为不一定有任何常量引用和一致安全的相对索引范围)
  • 无法正确检查/处理哨兵值
  • 与指针指向的数据类型有关的问题
    • 使用不安全/错误的强制转换(例如,需要动态强制转换时重新解释强制转换)
    • 没有意识到指针的索引是以指向类型的指针的大小为单位完成的
    • 从指针到较短整数类型的无效转换

A few cases come to mind:

  • continuing to access free()/delete()d memory or local variables after they've left scope
  • leaking heap memory due to unclear ownership
  • unintended shared access to data, where changes to pointed-to values may confuse some of algorithms working on them
    • accidental shallow copies
  • incomplete/flawed serialisation due to naive binary writing of assumed POD data that actually contains pointers to other data
  • multi-process unsafe data in shared memory where pointers (esp. virtual dispatch pointers) needed to be different in the different processes accessing it
  • cyclic data linkage that causes code to get stuck in loops indefinitely
  • moving the pointers through data in such a way that they accidentally move outside the data (the issue is similar to array indices, but more complex as there's not necessarily any constant reference and consistently safe relative indexing range)
  • failing to check for / handle sentinel values correctly
  • issues with the type of data to which the pointer points
    • use of unsafe/erroneous casts (e.g. a reinterpret cast where a dynamic cast is needed)
    • failure to appreciate that indexing from pointers is done in units of the pointer-to-type's size
    • invalid conversions from pointers to/from shorter integer types
纸短情长 2024-10-16 01:56:25

我见过的最令人讨厌的是“延迟故障”,即错误执行的写入访问会损坏稍后使用的数据结构,从而产生完全不相关的代码的错误输出。在调试过程中,您会观察到“机器的崛起”——数据结构神秘地获得了从未分配过的错误值,这违背了程序员的意愿。您可能正在搜索距离实际位置数千个 LOC 的错误。

The most nasty I have seen are "delayed failures", when the wrongly done write access damages a data structure that is used only later, producing incorrect output of the completely irrelevant code. During debugging, you observe "the rise of machines" - the data structure mysteriously obtains the wrong values that have never been assigned, against the programmers will. You may be searching for an error thousands of LOC away from where it really is.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文