我在我的程序中越来越多地使用指针,在阅读指针时,我发现的每一个指南或教程都说不正确地使用指针可能会产生“灾难性”的结果。
现在,我遇到了一些大内存泄漏的案例,指针取消引用了错误的指针变量,返回了不正确的值,但除此之外,没有发生任何“灾难性”事件;就像我的电脑和/或其他程序崩溃一样。
有人可以给我一个简单的代码示例,它肯定会产生“灾难性”的结果,也许还有一些发生的背景故事,以防你不小心使用了那段代码?我所说的“灾难性”结果是指可能会干扰其他程序或操作系统并可能使它们崩溃的代码。
我在我的程序中越来越多地使用指针,在阅读指针时,我发现的每一个指南或教程都说不正确地使用指针可能会产生“灾难性”的结果。
现在,我遇到了一些大内存泄漏的案例,指针取消引用了错误的指针变量,返回了不正确的值,但除此之外,没有发生任何“灾难性”事件;就像我的电脑和/或其他程序崩溃一样。
有人可以给我一个简单的代码示例,它肯定会产生“灾难性”的结果,也许还有一些发生的背景故事,以防你不小心使用了那段代码?我所说的“灾难性”结果是指可能会干扰其他程序或操作系统并可能使它们崩溃的代码。
不正确的指针算法也会导致灾难,因为错误的边界会导致缓冲区溢出,而缓冲区溢出会导致数据损坏,例如堆栈粉碎:
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
}
当然,只要调用strcpy
or memcpy
[*],您也可能犯同样的错误,您不必自己进行指针运算。如果攻击者控制了 的值i
(可能是因为它是从输入文件中读取的,并且攻击者制作了一个恶意文件),那么您可能会遇到比崩溃更糟糕的情况。结合更多特定于平台的技巧,攻击者可能能够安排返回i
最终执行攻击者提供的代码。
[*] or strncpy
, or strlcpy
, or strcpy_s
, or std::copy
, 在任何人开始之前。一旦你以某种方式遇到了错误,那么将错误绑定提供给边界检查函数仍然是错误的......
有两种主要的灾难——悬空指针和内存泄漏。
悬空指针是指指针存储的地址不是对象的地址:
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
悬空指针不好,因为使用它们会导致未定义的行为 - 程序可能会崩溃或修改一些不相关的数据,这将在以后引起问题。内存泄漏很糟糕,因为分配的内存无法重用,因此程序可能会在一段时间后内存不足。
想到几个案例:
我见过的最糟糕的是“延迟失败”,当错误地执行写入访问会损坏仅在以后使用的数据结构时,会产生完全不相关代码的错误输出。在调试过程中,您会观察到“机器的兴起”——数据结构神秘地获得了从未分配过的错误值,这违背了程序员的意愿。您可能正在寻找距实际位置数千个 LOC 的错误。