执行operator new的任何实现都返回指向大小为零的数组的保护页的指针

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

本文关键字:小为 数组 保护 指针 new operator 任何 实现 返回 执行      更新时间:2023-10-16

相关:c++ new int[0]——它会分配内存吗?

标准在5.3.4/7中说:

当direct-new-declarator中表达式的值为0时,调用分配函数分配一个没有元素的数组。

…并且,在3.7.3.1/2:

请求大小为0的指针解引用的效果是未定义的。

…但是,该指针不能为空指针。

由于实际解引用指针是未定义的行为,是否有任何实现返回指针到保护页?我想这会很容易,并且有助于检测错误/提高安全性。

我看了(草案)标准,我找不到任何明确禁止这一点的东西。不过,我猜答案是"不"。原因如下:

  • 正如你所说,new需要返回一个非空指针。
  • 此外,无论返回什么,传递给delete都必须是安全的。
  • 所以"随机值"不起作用,因为它会破坏删除。
  • 还要求每次调用返回不同的值(至少在它们被删除之前)-参见c++标准部分basic.stc.dynamic.allocation。在这一点上只有一个选择:返回"假指针",以某种方式被delete识别为"假指针"。

一种可能的实现可以通过保留一个未分页内存范围来实现,并且每次有人调用new int[0]时,它可以返回该范围内的不同地址(如果分配器保留全局计数器或类似的东西,则很容易做到)。

有利的一面是,您将获得立即检测这种类型指针上的解引用的能力。另一方面,您将失去检测双自由度的能力,因为指针上的delete操作实际上变成了no操作,并且对于所有正常情况,您将使new和delete操作更加复杂和缓慢。

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

Linux上的

gcc只分配少量内存并返回。我相信这是一种很标准的方式

为了跟踪需要释放多少内存,我查看或编写的大多数分配器如下所示:

void *malloc_example(size_t bytes) {Size_t *ret = get_memory(bytes + sizeof Size_t);/*查找空闲内存*/*ret = bytes;/*记住分配区域的大小*/Return (void *)(ret + 1);} 之前

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

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