free()
函数释放内存时,为什么这部分内存没有填充为零?是否有一种好的方法可以确保调用free()
时自动填充为零?我不想冒险将敏感数据留在释放回操作系统的内存中...
free()
函数释放内存时,为什么这部分内存没有填充为零?是否有一种好的方法可以确保调用free()
时自动填充为零?在释放内存块时将其清零会需要额外的时间。由于大多数情况下实际上并不需要,因此默认情况下不执行此操作。
如果您真的需要(比如您使用内存来存储密码或加密密钥),在释放块之前调用 memset()
。编写一个将 memset()
和 free()
链起来的实用函数也不是问题。
free()函数并不会将内存释放回操作系统,它将其释放回进程的堆管理器。为了提高效率,内存不会被清零。
当进程分配虚拟内存时,大多数操作系统会提供一个零页。这可以防止内存从一个进程“泄漏”到另一个进程,并引起像您提到的安全问题。
如果您在进程中有一些数据不想保留在内存中(例如用户密码),则需要自行将其清零。Windows提供了SecureZeroMemory API来实现这个功能。
memset(ptr, 0, size);
free(ptr);
我认为您需要这个...
如果你指的是像其他人假设的那样,将释放的内存块的每个字节都设置为0,那么你不能在释放内存块之后这样做。试图这样做会导致未定义的行为。因此,如果你这样做了,那么你对内存分配的理解存在严重误解。
但我猜当你说“我们在释放后将其设置为零”时,你可能是在谈论以下代码:
free(ptr);
ptr = NULL;
void free_and_clear(void **pptr) {
free(*pptr);
*pptr = NULL;
}
free_and_clear(&ptr);
#define FREE(x) do { free(x); x = NULL; } while(0);
这样,你就可以在不使用“&”运算符的情况下调用它。 - Chris Lutz最初的C语言设计理念是尽可能减少隐式效应。如果程序员希望在指向的内存被释放后将指针清零,那么这就是程序员需要编写的代码。我们中的一些人通常会使用像这样的宏:
#define FREE(P) ((void)(free((P)), (P) = NULL))
FREE
的表达式具有副作用,那么就会引发一系列问题...NULL
并不能解决OP的安全问题。指针所指向的内存仍然包含原始数据,即使该内存现在可以重新分配且不再有指针指向它。 - 6equj5free()
之前自行进行操作。如果您尝试在free()
之后进行操作,则不能保证它没有被重新分配。例如,您可以使用memset()
进行操作。
free()
不能保证清除内存,因为C语言不保证malloc()
会返回初始化的内存。无论如何,在分配内存后都必须自己进行初始化,因此在free()
时清除它是没有意义的。C最初是作为系统实现语言而设计的,因此C操作通常尽可能快速和接近底层。设计哲学中的一个关键点是,您可以将多个快速操作合并为一个较慢且更安全的操作,但您无法将较慢和更安全的操作合并为更快的操作。
如果您想要一个零成本函数,可以编写一个并使用它代替free()
。如果您关心安全性,我建议这样做。
将已释放指针的结果设置为零可能看起来像胡说八道,但是如果稍后无意中访问该指针,则会收到段错误(至少在真实的操作系统中),并且调试器将指出发生这种可怕情况的位置。但正如其他人所指出的,当您稍后调用“free”时,所有“free”都有要释放的地址,没有其他内容。