realloc使用起来安全吗?

16

之前我的一个朋友告诉我不要使用 realloc ,因为它是不安全的,但他不能告诉我原因,所以我对这个问题进行了一些研究,最接近我的怀疑的参考资料是:

  1. 第一篇文章
  2. 第二篇文章

我想知道是否可以在我的代码中继续使用 realloc ,如果它不安全,是否有其他方法来重新分配内存?


4
你知道Linux不保留内存吗?mallocrealloc永远不会失败。相反,如果你的内存用完了,程序就会崩溃。 - unixman83
4个回答

27

使用realloc是完全安全的。这是C程序中重新分配内存的方法。

然而,您应该始终检查返回值以检测错误条件。不要陷入这种常见陷阱:

p = realloc(p, new_size); // don't do this!

如果realloc失败,会返回NULL,你将无法访问p。因此请使用以下方式:
new_p = realloc(p, new_size);
if (new_p == NULL)
    ...handle error
p = new_p;

这取决于你的C库。一些realloc的实现只是做一个mallocmemcpyfree的操作。这使得realloc变得不太有用... - unixman83

16
两篇文章中的第一篇提出了两个投诉,超出了在此已经提到的“检查调用是否成功”的点。当这样做时,旧内容被丢弃并留在内存中的某个位置。对于需要擦除所有数据痕迹的安全内存应用程序,此行为是不合适的。如果您要存储敏感数据(例如私钥、未散列的密码等)并希望使攻击者更难恢复数据或其他系统进程窃取数据,则这是一个有效的观点。
由于它移动内存,因此任何指向该内存的旧指针都变得无效,可能会导致程序崩溃或以其他方式运行不正常。这一点对我来说似乎是毫无意义的。他们提出的解决方案也不好,他们malloc(),复制,然后free()原始代码具有相同的净效果-地址已更改。如果您想避免移动内存,则可以使用一些特定于平台的调用来执行此操作,如果您安排足够的空闲地址空间靠近它们,则可能做到这一点。如果您预先知道要保留多少地址空间,则您可能根本不会考虑首先调用realloc()!
除了“正确检查返回值”的点之外,第二篇文章中最有趣的观点是警告:
不要一次以1字节重新分配缓冲区。他们警告说:这肯定会使您的内存堆磨损。

这是一个可能有效的观点,但并不是对 realloc() 本身的批评; 如果你使用了 malloc()+复制+free(),同样会发生这种情况。真正的解决方法是合理地增长缓冲区,而不管如何增长它们或最好一开始就分配正确大小的块。

他们也有一些关于

使用 realloc 将内存返回给系统。

他们在这里是正确的,因为使用任何非零大小可能实际上不会使其返回。这可能不会使事情变得更糟,但是这种用法仍然看起来像是过早的“优化”的例子。解决方法仍然是使用合理的大小分配开始。

简而言之:它并不是不安全的,但它也不是解决所有问题的神奇解决方案。


6

realloc本身是安全的,但要安全使用它有点棘手——我会说大约85-90%的代码在使用它时都不安全。问题在于realloc返回NULL表示失败,但当它这样做时,你提供的指针仍然是有效的(前提是你没有将其分配大小调整为0)。

因此,只有当realloc返回非空指针时,你才需要将其返回值赋给你提供的指针。如果它返回null指针,则你之前的指针仍然有效,但分配未被调整大小。

另外请注意,许多人认为只有在增加分配时realloc才可能失败和/或移动分配。实际上,即使在减小分配大小时,它也可能失败(虽然这不太可能)或将数据移动到其他位置(更有可能)。


-2

就像 C 语言中的所有内容一样,只要你知道自己在做什么,就没问题。

(知道自己在做什么包括检查错误、不使用旧指针等)


1
我认为问题是“我需要做什么?”,所以这并没有真正回答它。 - Flexo
1
他说:“我想知道是否可以继续使用realloc。”答案是肯定的。 - asaelr
当我发表那条评论时,你的回答只有第一句话。 - Flexo
5
我反对“C语言中的一切都是好的”这种说法。C语言中有一个函数gets是永远不好的。当然,严格来说,现在C11已经成为了“C语言”,所以gets不再是“C语言中的”了。 :-) - R.. GitHub STOP HELPING ICE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接