繁体   English   中英

C ++ free()更改其他内存

[英]C++ free() changing other memory

我开始注意到有时在某些程序中分配内存时,它们会莫名其妙地崩溃。 我开始缩小罪魁祸首的范围,并提出一个示例,说明我难以理解的情况:

#include <iostream>
#include <stdlib.h>

using namespace std;

int main() {
char *tmp = (char*)malloc(16);
char *tmp2 = (char*)malloc(16);

long address = reinterpret_cast<long>(tmp);
long address2 = reinterpret_cast<long>(tmp2);
cout << "tmp = " << address << "\n";
cout << "tmp2 = " << address2 << "\n";

memset(tmp, 1, 16);
memset(tmp2, 1, 16);

char startBytes[4] = {0};
char endBytes[4] = {0};

memcpy(startBytes, tmp - 4, 4);
memcpy(endBytes, tmp + 16, 4);
cout << "Start: " << static_cast<int>(startBytes[0]) << " " << static_cast<int>(startBytes[1]) << " " << static_cast<int>(startBytes[2]) << " " << static_cast<int>(startBytes[3]) << "\n";
cout << "End: " << static_cast<int>(endBytes[0]) << " " << static_cast<int>(endBytes[1]) << " " << static_cast<int>(endBytes[2]) << " " << static_cast<int>(endBytes[3]) << "\n";
cout << "---------------\n";

free(tmp);

memcpy(startBytes, tmp - 4, 4);
memcpy(endBytes, tmp + 16, 4);
cout << "Start: " << static_cast<int>(startBytes[0]) << " " << static_cast<int>(startBytes[1]) << " " << static_cast<int>(startBytes[2]) << " " << static_cast<int>(startBytes[3]) << "\n";
cout << "End: " << static_cast<int>(endBytes[0]) << " " << static_cast<int>(endBytes[1]) << " " << static_cast<int>(endBytes[2]) << " " << static_cast<int>(endBytes[3]) << "\n";

free(tmp2);

return 0;
}

这是我看到的输出:

tmp = 8795380
tmp2 = 8795400
Start: 16 0 0 0
End: 16 0 0 0
---------------
Start: 17 0 0 0
End: 18 0 0 0

我正在使用Borland的免费编译器。 我知道我正在查看的标头字节是特定于实现的,并且“ reinterpret_cast”之类的东西是不好的做法。 我只是想找到答案的问题是:为什么“ End”的第一个字节从16变为18?

被视为“结束”的4个字节是tmp之后的16个字节,也就是tmp2之前的4个字节。 它们是tmp2的标头-为什么在tmp上调用free()会影响内存中的该位置?

我已经尝试过使用new []和delete []创建/删除tmp和tmp2的同一示例,并且出现相同的结果。

我们将不胜感激任何信息或帮助您理解为什么这个特定的内存位置受到影响。

您将不得不询问您的libc实现,为什么会更改。 无论如何,为什么重要呢? 这是libc尚未分配给您的内存区域,可能正在用于维护其自己的数据结构或一致性检查,或者根本没有使用。

基本上,您正在查看未分配的内存。 您不能对超出请求范围(即分配的16个字节)的内存发生了什么假设。 没有异常发生。

运行时和编译器可以随意使用它们进行任何操作,因此您不应在程序中使用它们。 运行时可能会更改这些字节的值以跟踪其内部状态。 取消分配内存极不可能使程序崩溃。 另一方面,像样例中那样访问已释放的内存是一个很大的编程错误,很可能会这样做。

避免这种情况的一种好方法是将所有可用的指针设置为NULL。 这样做会在访问释放的变量时强制程序崩溃。

从堆中删除分配的元素的行为可能会修改其他堆节点,或者该实现会保留一个或多个字节的标头,以用作先前分配中的保护字节。

内存管理器必须记住例如malloc已分配的内存块的大小。 有不同的方法,但最简单的方法可能是分配比调用中请求的大小多4个字节,并在指针返回给调用者之前存储大小值。

然后, free的实现可以从传递的指针中减去4个字节,以获得指向存储大小的指针,然后可以将该块链接到(例如)该大小的空闲可重用块的列表(可能会再次使用那些4个字节来存储到下一个块的链接)。

您不应更改甚至查看分配的区域之前/之后的字节。 访问(甚至只是用于读取)未分配的内存的结果是未定义行为(是的,确实,由于读取未分配的内存,您确实可以使程序真正崩溃或疯狂地运行)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM