【问题标题】:What are these so-called 'disasters' that improper use of pointers can cause? [closed]指针使用不当会导致这些所谓的“灾难”是什么? [关闭]
【发布时间】:2010-12-22 10:52:42
【问题描述】:

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

现在,我遇到了一些大内存泄漏的案例,并且指针取消引用了错误的指针变量,返回了不正确的值,但除此之外,没有发生任何“灾难性”事件;就像我的电脑和/或其他程序崩溃一样。

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

【问题讨论】:

  • 定义“灾难性”。滥用指针可能会导致程序中出现各种大错误,但在现代计算机上,最糟糕的情况是程序无法按预期运行。
  • 好吧,不要操作带有指针错误的程序的 X 光机。
  • @Peter Zion:我从各种来源阅读和听说过,不正确的指针使用实际上会导致您的系统崩溃。对于当今的计算机来说,这不再适用吗?也:编辑问题
  • @Peter Zion:使用无效指针是未定义的行为,它可以以任何方式表现出来。例如,如果您的程序使用 C++ 运行时,该运行时具有删除所有文件的函数,该函数可能会被调用。
  • @Arcenio:请看这个真实的答案:stackoverflow.com/questions/908872/… 通过网络发送敏感数据有时甚至比“崩溃”您的系统更糟糕。

标签: c++ memory pointers memory-management unsafe-pointers


【解决方案1】:

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

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 最终执行攻击者提供的代码。

[*] 或strncpy,或strlcpy,或strcpy_s,或std::copy,在任何人开始之前。一旦你以某种方式遇到了边界错误,那么将错误绑定提供给边界检查函数仍然是错误的......

【讨论】:

    【解决方案2】:

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

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

    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
    

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

    【讨论】:

    • +1。第一个通常比第二个差,这只会导致程序浪费内存(仅当程序打算长时间运行时才重要,例如服务器)。
    • @j_random_hacker:值得记住的是,泄漏的对象析构函数不会运行,这可能会改变程序的行为。
    • 可能是错字,或者我只是累了;但在您的第一个示例中,似乎 second 不是指针。这是故意的吗?
    【解决方案3】:

    想到几个案例:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-18
        • 2010-10-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-03
        • 1970-01-01
        相关资源
        最近更新 更多