C++ 这些所谓的';灾难';指针的不当使用会导致什么?

C++ 这些所谓的';灾难';指针的不当使用会导致什么?,c++,memory,pointers,memory-management,unsafe-pointers,C++,Memory,Pointers,Memory Management,Unsafe Pointers,我在我的程序中越来越多地使用指针,在阅读指针时,我发现的每一个指南或教程都说,不正确使用指针可能会产生“灾难性”的结果 现在,我遇到过一些大内存泄漏的情况,指针取消了对错误指针变量的引用,返回了错误的值,但除此之外,从未发生过“灾难性”事件;比如我的电脑和/或其他程序崩溃 有人能给我一个简单的代码示例,它肯定会产生“灾难性”的结果,也许会有一些发生的背景故事,以防您曾经意外地使用过那段代码?所谓“灾难性”结果,我指的是可能干扰其他程序或操作系统,并可能使其崩溃的代码。有两种主要的灾难-悬空指针和

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

现在,我遇到过一些大内存泄漏的情况,指针取消了对错误指针变量的引用,返回了错误的值,但除此之外,从未发生过“灾难性”事件;比如我的电脑和/或其他程序崩溃


有人能给我一个简单的代码示例,它肯定会产生“灾难性”的结果,也许会有一些发生的背景故事,以防您曾经意外地使用过那段代码?所谓“灾难性”结果,我指的是可能干扰其他程序或操作系统,并可能使其崩溃的代码。

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

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

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
T*对象;
对于(int i=0;i<10;i++){
object=newt();
}
删除对象;//现在,前九个对象是不可检查的

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

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

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

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
T*对象;
对于(int i=0;i<10;i++){
object=newt();
}
删除对象;//现在,前九个对象是不可检查的

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

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

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
}
void test\u fun(int i)
int x[5];
对于(int*p=x;p
当然,只要调用
strcpy
memcpy
[*],您就可能犯同样的错误,您不必自己进行指针运算。如果攻击者控制
i
的值(可能是因为它是从输入文件读取的,并且攻击者创建了一个恶意文件),那么您可能会遇到比崩溃更严重的问题。结合更多特定于平台的技巧,攻击者可能能够安排返回到
i
最终执行攻击者提供的代码


[*]或
strncpy
,或
strlcpy
,或
strcpy
,或
std::copy
,在任何人开始之前。一旦您以某种方式获得了错误的绑定,那么向边界检查函数提供错误的绑定仍然是错误的…

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

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
}
void test\u fun(int i)
int x[5];
对于(int*p=x;p
当然,只要调用
strcpy
memcpy
[*],您就可能犯同样的错误,您不必自己进行指针运算。如果攻击者控制
i
的值(可能是因为它是从输入文件读取的,并且攻击者创建了一个恶意文件),那么您可能会遇到比崩溃更严重的问题。结合更多特定于平台的技巧,攻击者可能能够安排返回到
i
最终执行攻击者提供的代码


[*]或
strncpy
,或
strlcpy
,或
strcpy
,或
std::copy
,在任何人开始之前。一旦您以某种方式获得了一个错误的绑定,那么将该错误绑定提供给边界检查函数仍然是错误的…

我想到了一些情况:

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