为什么malloc真的不确定? (的Linux / Unix)

时间:2012-06-28 19:34:53

标签: c linux-kernel malloc non-deterministic

malloc 不保证返回0的内存。传统观点不仅如此,而且内存 malloc 返回的内容实际上是non-deterministic,例如openssl used them for extra randomness

但是,据我所知, malloc 建立在 brk / sbrk 之上,它会“返回”0'ed内存。 我可以看到为什么 malloc 返回的内容可能是非0 ,例如来自以前的免费内存,但为什么它们会在“普通”单线程软件中成为non-deterministic

  1. 传统智慧是否真实(假设相同的二元和库)
  2. 如果是,为什么?
  3. 编辑有几个人回答解释为什么内存可能非0,我已在上面的问题中解释过。我问的是为什么使用malloc返回的内容的程序可能是非确定性的,也就是为什么它每次运行时都会有不同的行为(假设相同的二进制文件和库)。 非0确实不会暗示非确定性行为。换句话说:为什么每次运行二进制文件时它都会有不同的内容。

10 个答案:

答案 0 :(得分:11)

Malloc并非保证不可预测性......它只是不能保证可预测性。

E.g。考虑一下

 return 0;

是malloc的有效实现。

答案 1 :(得分:4)

malloc返回的内存的初始值未指定,这意味着C和C ++语言的规范对可以传回的值没有限制。这使得该语言更易于在各种平台上实现。虽然在Linux malloc中使用brksbrk实现并且内存应该归零(但我甚至不确定这是否一定是真的,顺便说一下)可能是真的在其他平台上,也许是一个嵌入式平台,没有理由这样做。例如,嵌入式设备可能不希望将内存归零,因为这样做会花费CPU周期,从而耗费功率和时间。此外,为了提高效率,例如,内存分配器可以回收先前已被释放的块而不首先将它们归零。这意味着即使来自OS的内存最初被清零,也不需要来自malloc的内存。

传统观念认为价值观是不确定的,这可能是一个很好的理由,因为它迫使你意识到你得到的任何记忆都可能包含垃圾数据,这可能会导致程序崩溃。也就是说,你不应该假设这些值是真正随机的。但是,你应该意识到,交还的价值并不是你想要的。您有责任正确设置它们。假设这些值是真正随机的是一个真正糟糕的想法,因为没有什么可以暗示他们会这样。

如果您希望保证内存清零,请改用calloc

希望这有帮助!

答案 2 :(得分:3)

malloc在许多可以用C / C ++编程的系统上定义,包括许多非UNIX系统,以及许多完全缺乏操作系统的系统。要求malloc将内存清零会违背C的尽可能节省CPU的理念。

标准提供归零校准calloc,如果您需要将内存清零,可以使用该校准。但是,如果您计划在获得内存时自己初始化内存,那么确保将块清零的CPU周期是浪费; C标准旨在尽可能地避免这种浪费,通常是以牺牲可预测性为代价。

答案 3 :(得分:3)

malloc返回的内存未归零(或者更确切地说,保证归零),因为它不需要。重用从您自己的进程的地址空间或页面池中提取的未初始化内存不存在安全风险。你已经知道了,你已经知道了内容。实际意义上的内容也没有问题,因为无论如何你都要覆盖它。

在第一次分配时,由malloc 返回的内存归零,因为操作系统内核无法承担给另一个进程拥有的进程数据的风险。因此,当操作系统在新页面中出现故障时,它只提供已归零的操作系统。但是,这与malloc完全无关。

(稍微偏离主题:你提到的Debian安全事件比使用未初始化的内存随机性更具有一些含义。一个不熟悉代码内部工作原理并且不知道修补后的确切含义的打包者Valgrind报告过的几个地方,可能是出于好意,但却产生了灾难性的后果。其中包括“从未经过处理的记忆中随意”,但它并不是最严重的记忆。)

答案 4 :(得分:2)

我认为它是非确定性的假设是完全错误的,特别是当您要求非线程上下文时。 (由于调度问题,在线程上下文中你可能会有一些非确定性)。

试一试。

创建一个顺序的,确定性的应用程序
  • 做了大量的分配
  • 用一些模式填充内存,例如用计数器的值填充
  • 释放这些分配的每一秒
  • 新分配相同金额
  • 运行这些新分配并在文件中注册第一个字节的值(每行一个文本编号)

运行此程序两次,并将结果注册到两个不同的文件中。我的想法是这些文件是完全相同的。

答案 5 :(得分:1)

即使在“普通”单线程程序中,内存也会被释放并重新分配多次。 Malloc会回复你以前用过的记忆。

答案 6 :(得分:1)

即使是单线程代码也可以执行malloc然后释放malloc并恢复以前使用的非零内存。

答案 7 :(得分:1)

无法保证brk / sbrk返回已删除的数据;这是一个实现细节。对于操作系统而言,这通常是好主意,以降低来自一个进程的敏感信息进入另一个进程的可能性,但规范中没有任何内容表明情况会如此。< / p>

此外,mallocbrk / sbrk之上实施的事实也取决于实现,甚至可以根据分配的大小而变化;例如,Linux上的大量分配传统上使用/ {/ 0}上的mmap

基本上,你既不能依赖包含垃圾的malloc() ed区域,也不能依赖于全0,并且任何程序都不应该采用这种方式或其他方式。

答案 8 :(得分:0)

我能想出答案的最简单方法是:

如果我正在寻找用于绘制壁画的墙面空间,我不在乎它是白色的还是覆盖着旧的涂鸦,因为我要将它涂在上面并涂上它。我只关心我是否有足够的平方英尺来容纳图片,而且我不在乎我不是在一个属于他人的区域上画画。

这就是malloc的想法。每次进程结束时将内存归零都会浪费计算量。这就像每次完成绘画时重新启动墙壁一样。

答案 9 :(得分:-1)

计算机内存中存在整个程序生态系统,您无法控制mallocs和frees发生的顺序。

想象一下,第一次运行应用程序和malloc()时,它会给你一个带有垃圾的地址。然后你的程序关闭,你的操作系统将该区域标记为空闲。另一个程序使用另一个malloc(),写了很多东西,然后离开。你再次运行你的程序,可能会发生malloc()给你相同的地址,但现在有不同的垃圾,以前的程序可能写的。

我实际上并不知道任何系统中malloc()的实现,我不知道它是否实现了任何类型的安全措施(比如随机化返回的地址),但我不这么认为。

这是非常确定的。