在 Nicholas Ormrod 在 CppCon 2016 的演讲中,他提到了 Facebook 的一个阴险的错误,即从未初始化(未写入)的页面读取单个字节两次,因此在某些情况下第二次读取返回一个(非零) )值与第一次读取的值(零)不同。
他提到他们使用了jemalloc,并且我也推测他们在Linux上运行。 jemalloc 的手册页说它总是更喜欢
mmap()
而不是 sbrk()
。
现在,jemalloc 唯一的
mmap()
调用 使用标志 MAP_PRIVATE | MAP_ANONYMOUS
,偶尔包含 MAP_FIXED
,特别是它不使用 MAP_UNINITIALIZED
。这意味着页面在分配时总是零初始化。
madvise()
与 MADV_DONTNEED
也会返回 “零填充按需页面”,我将其理解为“零初始化页面”。
我的问题是:第二次读取怎么可能返回非零值,从而导致错误?
无论这些人提供什么解释都是完全错误的(至少在给定的上下文中)。无论如何,代码都有未定义的行为。
如果
data
指向分配了至少 size()
+ 1 大小的块,则由于竞争条件,代码具有未定义的行为(他之前提到过线程的使用)。
如果
data
的大小小于该值(例如,等于 size()
),则由于越界访问,代码具有未定义的行为(并且竞争条件成为有争议的点)。
if (data[size] != '\0')
data[size] = '\0';
这很简单,因为在第一次写入之前,它总是尝试读取它,而
data[size]
仍未初始化,因为\0
是懒惰地写入FB字符串中的