operator new return 的任何实现是否指向零大小数组的保护页的指针?

Do any implementations of operator new return a pointer to a guard page for zero-size arrays?

相关:C++ new int[0] -- will it allocate memory?

标准说,在 5.3.4/7 中:

When the value of the expression in a direct-new-declarator is zero, the allocation function is called to allocate an array with no elements.

...并且,在 3.7.3.1/2 中:

The effect of dereferencing a pointer returned as a request for zero size is undefined.

...但是,指针不能是空指针。

由于实际上取消引用指针是未定义的行为,任何实现 return 是否指向保护页的指针?我想这会很容易,并有助于检测 bugs/improve 安全性。

我查看了(草案)标准,但找不到任何明确禁止这样做的内容。不过,我猜答案是 "no"。这就是为什么:

  • 正如你所说,new 需要 return 一个非空指针。
  • 此外,无论什么 returns 都必须安全地传递给删除。
  • 所以 "random value" 将不起作用,因为它会中断删除。
  • 还需要为每个调用 return 不同的值(至少在它们被删除之前)- 请参阅 C++ 标准部分 basic.stc.dynamic.allocation。
  • 此时只剩下一个选项:return "fake pointers" 以某种方式被删除识别为 "fake pointers".

一个可能的实现可以通过保留一系列未分页的内存来完成,并且每次有人调用 new int[0] 它可以 return 该范围内的不同地址(如果分配器保持全局计数器或类似的东西)。

从好的方面来说,您将能够立即检测到对此类指针的取消引用。另一方面,您将失去检测双重释放的能力,因为指针上的 delete 实际上变成了无操作,并且对于所有正常情况,您将使 new 和 delete 变得更加复杂和缓慢。

所以因为这很​​棘手,而且弊大于利,我非常有信心没有人这样做。

linux 上的 gcc 只分配少量内存,return 就是这样。我相信这几乎是执行此操作的标准方法。

为了跟踪需要释放多少内存,我查看或编写的大多数分配器看起来像这样:

 void *malloc_example( size_t bytes ) {
     size_t *ret = get_memory(bytes + sizeof size_t);   /* find free memory */
     *ret = bytes;                /* remember size of allocated area */
     return (void *)( ret + 1 );
 }

因此,当您分配零长度块时,您实际上会在返回给您的地址之前得到一个偷偷摸摸的词。这也确保为每个分配分配一个唯一的地址。这很重要,指向零长度块的专用保护内存更像是一种浪费,因为每个空闲必须测试我的经验所说的罕见情况。

一些调试分配器包括捕获双重释放、内存泄漏、捕获先前缓冲区溢出的保护字等的额外开销。此外,指向一些神奇内存会使此类调试更加困难。