8

malloc不能保证返回 0'ed 内存。传统观点不仅如此,而且内存malloc返回的内容实际上是非确定性的,例如openssl 将它们用于额外的随机性

然而,据我所知,malloc建立在brk/sbrk之上,它“返回”0'ed内存。我可以看到为什么malloc返回的内容可能是非 0,例如来自以前释放的内存,但为什么它们在“普通”单线程软件中是不确定的?

  1. 传统智慧真的是真的吗(假设相同的二进制文件和库)
  2. 如果是这样,为什么?

编辑有几个人回答解释了为什么内存可以为非0,我已经在上面的问题中解释过。我要问的是为什么使用 malloc 返回的内容的程序可能是不确定的,即为什么它每次运行时都会有不同的行为(假设相同的二进制文件和库)。非 0 不暗示非确定性行为。换一种说法:为什么每次运行二进制文件时它都有不同的内容。

4

10 回答 10

11

Malloc 不保证不可预测性……它只是不保证可预测性。

例如,考虑一下

 return 0;

是 malloc 的有效实现。

于 2012-06-28T19:38:46.687 回答
4

返回的内存的初始值malloc是未指定的,这意味着C和C++语言的规范对可以返回的值没有任何限制。这使得该语言更容易在各种平台上实现。虽然在 Linuxmalloc中使用brk和实现可能是真的sbrk并且内存应该归零(顺便说一句,我什至不确定这是否一定是真的),在其他平台上,也许是嵌入式平台,没有理由必须如此。例如,嵌入式设备可能不想将内存归零,因为这样做会消耗 CPU 周期,从而消耗功率和时间。此外,为了提高效率,例如,内存分配器可以回收先前已释放的块,而无需先将它们清零。这意味着即使来自操作系统的内存最初被清零,来自的内存malloc也不需要。

值是非确定性的传统观点可能是一个很好的观点,因为它迫使您意识到您返回的任何内存都可能包含可能导致程序崩溃的垃圾数据。也就是说,您不应该假设这些值是真正随机的。但是,您应该意识到,返回的值不会神奇地成为您想要的。您有责任正确设置它们。假设这些值是真正随机的是一个非常糟糕的主意,因为根本没有任何迹象表明它们会是随机的。

如果您想要保证清零的内存,请calloc改用。

希望这可以帮助!

于 2012-06-28T19:40:23.450 回答
3

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

该标准提供了一个归零校准calloc,如果您需要将内存归零,可以使用该校准。但是,如果您打算在获得内存后立即自己初始化内存,则确保将块清零所花费的 CPU 周期是一种浪费;C 标准旨在尽可能地避免这种浪费,通常以牺牲可预测性为代价。

于 2012-06-28T19:39:51.553 回答
3

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

顺便说一句,返回的内存在第一次分配malloc 归零,因为操作系统内核无法承担将一个进程数据提供给另一个进程先前拥有的风险的风险。因此,当操作系统在新页面中出现故障时,它只会提供已归零的页面。然而,这与malloc.

(有点题外话:你提到的 Debian 安全问题比使用未初始化的内存来实现随机性有更多的含义。一个不熟悉代码内部工作并且不知道确切含义的打包者修补了几个地方Valgrind 报告的,大概是出于好意,但结果却是灾难性的。其中有“来自未初始化记忆的随机事件”,但它远不是最严重的。)

于 2012-06-28T19:40:38.553 回答
2

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

试试看。创建一个顺序的、确定性的应用程序

  • 做了一大堆分配
  • 用某种模式填充内存,例如用计数器的值填充它
  • 释放这些分配的每一秒
  • 新分配相同的金额
  • 运行这些新分配并注册文件中第一个字节的值(作为每行一个文本数字)

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

于 2012-06-28T20:22:48.000 回答
1

即使在“正常”的单线程程序中,内存也会被多次释放和重新分配。Malloc 会返回给你之前使用过的内存。

于 2012-06-28T19:39:04.610 回答
1

甚至单线程代码也可以先执行 malloc 然后释放然后 malloc 并取回以前使用的非零内存。

于 2012-06-28T19:39:27.937 回答
1

不保证brk/sbrk返回 0ed-out 数据;这是一个实现细节。对于操作系统来说,这样做通常是一个好主意,以减少来自一个进程的敏感信息进入另一个进程的可能性,但规范中没有任何内容表明会出现这种情况。

此外,在/malloc之上实现的事实也是依赖于实现的,甚至可以根据分配的大小而变化;例如,Linux 上的大分配传统上使用/dev/zero 来代替。brksbrkmmap

基本上,您既不能依赖malloc()包含垃圾的 ed 区域,也不能依赖它全为 0,并且任何程序都不应该假设一种或另一种方式。

于 2012-06-28T19:39:53.893 回答
0

我能想到的最简单的答案是这样的:

如果我正在寻找墙壁空间来画壁画,我不在乎它是白色的还是被旧涂鸦覆盖的,因为我要给它打底并在上面画画。我只关心我是否有足够的平方英尺来容纳这幅画,我关心的是我没有在属于别人的区域上绘画。

malloc就是这么想的。每次进程结束时将内存归零将浪费计算量。这就像每次完成绘画时都要重新涂刷墙壁。

于 2012-06-28T19:56:33.547 回答
-1

计算机内存中有一个完整的程序生态系统,您无法控制 malloc 和 free 发生的顺序。

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

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

这是非常确定的。

于 2012-06-28T20:22:24.730 回答