为什么free()在释放之前没有将内存清零?

当我们在C中free()内存时,为什么那个内存没有填充零? 在调用free()时,有没有一种方法可以确保这种情况发生?

我宁愿不冒险将内存中的敏感数据释放回操作系统……

释放存储器块时将其清零将需要额外的时间。 由于大部分时间实际上没有必要,因此默认情况下不会这样做。

如果你确实需要(假设你使用内存来存储密码或加密密钥) – 在释放块之前调用memset() 。 编写链接memset()free()的实用程序函数也不是问题。

C为什么在自由实现中内存没有明确地设置为零。

因为速度快。

因为我们释放了内存后我们如何在释放后将其设置为零。

嗯?

如果你想在释放内存时将内存设置为0,你必须 free()之前自己做。 如果你在free()之后尝试它,则无法保证它没有再次分配。 例如,您可以使用memset()

free()不保证将清除内存,因为C不保证malloc()将返回初始化内存。 无论哪种方式,你必须在分配之后自己初始化它,所以当它是free()时候清除它没有意义free() ‘d

最初的C哲学是将隐含效应保持在绝对最小值。 如果程序员想要在释放指向的内存后将指针归零,那就是程序员应该写的东西。 我们这些经常使用像这样的宏的人:

 #define FREE(P) ((void)(free((P)), (P) = NULL)) 

当然,如果传递给FREE的表达式有副作用,那么刚开了一大堆蠕虫……

free()不会将内存释放回操作系统 – 它会释放回进程的堆管理器。 出于效率原因,它并非零。

当进程分配虚拟内存时,大多数操作系统会将其归为零页面。 这可以防止内存从一个进程“泄漏”到另一个进程并导致像您提到的安全问题。

如果您的进程中有数据不想保留在内存中(例如,用户的密码),则您有责任将其清零。 Windows为此提供了SecureZeroMemory API。

[编辑:这是试图回答原始海报的问题。 shog9的编辑可能会或可能没有改变这个问题 – 很难说因为原版不清楚……

如果你的意思是,正如其他人所假设的那样,为被释放的内存块的每个字节设置0,那么在释放块之后就不能这样做了。 尝试这样做会产生不确定的行为。 所以,如果你这样做,那么你就会严重误解内存分配。

但我猜你说“我们在释放后将它设置为零”,你可能会谈论这样的代码:

 free(ptr); ptr = NULL; 

如果是这样,那么free的原因不能将ptr设置为NULL,那就是free只接收来自变量ptr的值。 它没有办法修改ptr,因为你没有将变量ptr本身传递给free。 您只是传递当前存储在其中的地址。 这是C语言设计的一部分 – 当你调用一个传递值的函数时,被调用者无法告诉该值是如何计算的,或者调用者的代码中可能包含哪个变量。 即使有可能,对这个语言规则的例外是免费的也是疯狂的。

无论如何,并不是每个人在释放它们之后都会将指针归零。 有些人认为这是一个很好的安全措施,其他人则认为不是。 无论你如何看待它,代码都不会将内存归零,它只会将指针归零到内存。 如果你想编写一个为你清除指针的函数,那么你可以:

 void free_and_clear(void **pptr) { free(*pptr); *pptr = NULL; } 

然后像这样使用它:

 free_and_clear(&ptr); 

请注意,这会传递指向变量ptr的指针,而不是ptr的值。 所以free_and_clear可以修改ptr。 但是这对你如何使用它有一些限制,这些限制不适用于free – 你需要一个指向可修改值的指针,而不仅仅是一个值。

 memset(ptr, 0, size); free(ptr); 

我想你想要这个……

C最初是作为系统实现语言设计的,因此C操作通常尽可能快且尽可能接近金属。 设计理念中的一个关键点是,您可以采取多种快速操作,并将它们组合成一种更慢,更安全的操作,但您不能采取更慢,更安全的操作并使其更快。

如果你想要一个零和自由函数,你可以写一个,并使用它而不是free() 。 如果你担心安全问题,我会推荐它。

一个非常具体的答案问题“为什么在释放后将内存设置为0?” 是“因为语言规范没有定义该行为。

从草案ANSI C规范:“自由函数导致ptr指向的空间被释放,即可用于进一步分配。”

将释放指针的结果设置为零似乎是废话,但如果稍后无意中访问指针,您将获得段错误(至少在实际操作系统中),并且调试器将指向这种憎恶发生的位置。 但正如其他人所指出的那样,当你以后称之为“免费”时,所有免费的都是免费的地址,而不是别的。

如果我正确地理解了这个问题,那么OP希望不要将敏感信息“留在那里”而担心它会受到损害。 正如之前的海报所指出的,在释放之前释放内存是擦除数据的答案。

然而,它远不是OP试图实现的答案。 对于初学者来说,将内存归零在保护应用程序方面毫无用处。 即使将内存页面分配给另一个正在运行的进程,在大多数操作系统中,此过程也是不确定的,并且没有理智的黑客会使用这种技术来破坏您的数据。

一个理智的黑客会做的是将你的程序打入反汇编程序并通过它进行调试,直到找出数据的位置然后使用它。 因为一旦你是一个称职的反汇编程序(是的,反汇编程序:),对memset的调用就显得非常明显了。我们假设的黑客只会在memset发生之前获取数据。

要真正回答你的问题。 如果您试图保护C程序中的某些敏感数据,那么您将进入远远超出正常C / C ++程序员(如我自己)的领域,进入编写虚拟机以执行数据敏感操作的领域。

你甚至提出这个问题的事实意味着你开发一些需要这种保护水平的东西是不计后果的。 它绝对不是保护数据的第一站。 首先选择低悬的水果,网上有大量关于此的信息。

这是一个常见问题解答: 为什么在免费调用后指针不为null?

因为这会浪费时间。

一旦使用free()释放内存,在该特定地址分配的值和内存将被删除(释放),但指针仍指向该地址。 如果您尝试取消引用该指针,则会出现Segmentation fault或Bus error。 因此,一旦指针指向的内存被释放,就可以安全地为指针分配NULL值。 您可以在空闲后将 < 设置变量设置为NULL >

还有bzero(3)。