C++ 中的双重释放或损坏错误
本文将讨论 C++ 中动态内存分配中出现的问题。在使用堆内存时,我们会遇到许多在进行堆内存管理时非常重要的问题。
首先,我们将讨论如何分配内存以及 C++ 中提供的不同方法;然后,我们将探讨 C++ 中出现 double free or corruption
错误的原因和解决方案。
C++ 中的动态内存分配和释放
C++ 允许我们在运行时分配变量或数组内存。这称为动态内存分配。
在其他编程语言中,例如 Java 和 Python,编译器会自动维护变量内存。但是,在 C++ 中并非如此。
在 C++ 中,我们必须在不再需要动态分配的内存后手动释放它。我们可以使用 new
和 delete
函数动态分配和释放内存。
还有另外两个函数,即 malloc
和 free
,它们也包含在 C++ 中,用于动态内存分配和释放。
参考下面的示例,演示 new
和 delete
函数的使用。
#include <iostream>
using namespace std;
int main() {
int* ptr;
ptr = new int;
*ptr = 40;
cout << *ptr;
delete ptr;
return 0;
}
我们使用’new’操作符为一个 int
变量动态分配内存。值得注意的是,我们使用了引用变量 ptr
来动态分配内存。
new
运算符返回内存位置的地址。在数组的情况下,new
运算符返回数组第一个元素的地址。
在我们不再需要使用动态声明的变量后,我们可以释放它所使用的内存。delete
运算符用于此目的。
它将内存返回给操作系统。这称为内存释放。
下一个示例将向你展示 malloc
和 free
函数的演示。
#include <iostream>
#include <cstdlib>
using namespace std;
int main() {
int* ptr2 = (int*) malloc(sizeof(int));
*ptr2 = 50;
cout << *ptr2;
free(ptr2);
return 0;
}
在 C++ 中,malloc()
方法分配一个指向未初始化内存块的指针。cstdlib
头文件定义它。
malloc
将需要分配的内存大小作为参数,并返回一个指向已分配内存块的 void 指针。因此可以根据我们的要求进行类型转换。
另一方面,free()
方法释放使用 malloc
函数分配的内存。它将内存返回给操作系统并避免内存泄漏问题。
C++ 中的双重释放或损坏
错误
当多次使用 free()
且内存地址作为输入时,会发生双重释放错误。
在同一个变量上调用 free()
两次可能会导致内存泄漏。当软件使用相同的参数运行两次 free()
时,应用程序中的内存管理数据结构会损坏,从而允许恶意用户在任何内存区域中写入值。
在某些情况下,这种损坏可能导致程序崩溃或更改执行流程。攻击者可以通过覆盖特定的寄存器或内存区域来误导程序执行他们选择的代码,从而产生具有提升权限的交互式 shell。
当缓冲区被 free()
重新组织和组合空闲内存块(以在将来分配更大的缓冲区)时,将读取空闲缓冲区的链接列表。这些块被组织在一个双链表中,其中包含指向它们之前和之后的块的链接。
攻击者可能通过断开未使用的缓冲区(在调用 free()
时发生)、有效地覆盖有价值的寄存器并从其缓冲区启动 shellcode 来在内存中写入任意值。
参考下面的一个例子。
#include <iostream>
#include <cstdlib>
using namespace std;
int main() {
int* ptr2 = (int*) malloc(sizeof(int));
*ptr2 = 50;
cout << *ptr2;
free(ptr2);
free(ptr2);
return 0;
}
输出:
free(): double free detected in cache 2
Aborted
在上面的代码片段中,我们两次使用了 free()
函数,这意味着我们正在尝试释放已经空闲且不再分配的内存。这会产生内存泄漏问题,并且是导致代码崩溃的根本原因。
还有许多其他情况可能会遇到此类错误。但是双重释放漏洞有三个常见(并且经常重叠)的原因。
-
错误情况和其他异常情况
2、内存空间释放后,使用。 - 不清楚程序的哪个部分负责内存释放
虽然一些双重释放漏洞并不比前面的例子复杂多少,但它们大多分布在数百行代码甚至多个文件中。程序员似乎特别容易多次释放全局变量。
如何避免 C++ 中的双重释放或损坏
错误
这种类型的漏洞可以通过在指针空闲时将其分配给 NULL
来避免(即,该指针指向的内存空闲)。之后,大多数堆管理器都会忽略空闲的空指针。
建议将所有已删除的指针置空,并在释放它之前检查引用是否为 null
。在我们的代码开始处,我们必须在任何情况下使用该指针之前初始化 null
指针。
相关文章
在 C++ 中通过掷骰子生成随机值
发布时间:2023/04/09 浏览次数:169 分类:C++
-
本文解释了如何使用时间因子方法和模拟 C++ 中的掷骰子的任意数方法生成随机数。了解它是如何工作的以及它包含哪些缺点。提供了一个 C++ 程序来演示伪数生成器。
在 C++ 中使用模板的链表
发布时间:2023/04/09 浏览次数:158 分类:C++
-
本文解释了使用模板在 C++ 中创建链表所涉及的各个步骤。工作程序演示了一个链表,该链表使用模板来避免在创建新变量时声明数据类型的需要。
在 C++ 中添加定时延迟
发布时间:2023/04/09 浏览次数:142 分类:C++
-
本教程将为你提供有关在 C++ 程序中添加定时延迟的简要指南。这可以使用 C++ 库为我们提供的一些函数以多种方式完成。
在 C++ 中创建查找表
发布时间:2023/04/09 浏览次数:155 分类:C++
-
本文重点介绍如何创建查找表及其在不同场景中的用途。提供了三个代码示例以使理解更容易,并附有代码片段以详细了解代码。
如何在 C++ 中把字符串转换为小写
发布时间:2023/04/09 浏览次数:63 分类:C++
-
介绍了如何将 C++ std::string 转换为小写的方法。当我们在考虑 C++ 中的字符串转换方法时,首先要问自己的是我的输入字符串有什么样的编码
如何在 C++ 中确定一个字符串是否是数字
发布时间:2023/04/09 浏览次数:163 分类:C++
-
本文介绍了如何检查给定的 C++ 字符串是否是数字。在我们深入研究之前,需要注意的是,以下方法只与单字节字符串和十进制整数兼容。
如何在 c++ 中查找字符串中的子字符串
发布时间:2023/04/09 浏览次数:65 分类:C++
-
本文介绍了在 C++ 中检查一个字符串是否包含子字符串的多种方法。使用 find 方法在 C++ 中查找字符串中的子字符串
如何在 C++ 中把字符串转换为 Char 数组
发布时间:2023/04/09 浏览次数:107 分类:C++
-
本文介绍了在 C++ 中把字符串转换为 char 数组的多种方法。使用 std::basic_string::c_str 方法将字符串转换为 char 数组