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 );
}
因此,当您分配零长度块时,您实际上会在返回给您的地址之前得到一个偷偷摸摸的词。这也确保为每个分配分配一个唯一的地址。这很重要,指向零长度块的专用保护内存更像是一种浪费,因为每个空闲必须测试我的经验所说的罕见情况。
一些调试分配器包括捕获双重释放、内存泄漏、捕获先前缓冲区溢出的保护字等的额外开销。此外,指向一些神奇内存会使此类调试更加困难。
相关: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 ); }
因此,当您分配零长度块时,您实际上会在返回给您的地址之前得到一个偷偷摸摸的词。这也确保为每个分配分配一个唯一的地址。这很重要,指向零长度块的专用保护内存更像是一种浪费,因为每个空闲必须测试我的经验所说的罕见情况。
一些调试分配器包括捕获双重释放、内存泄漏、捕获先前缓冲区溢出的保护字等的额外开销。此外,指向一些神奇内存会使此类调试更加困难。