gflags 配置为仅启用“启用堆尾检查”。未启用 PageHeap。
c:\Program Files (x86)\Windows Kits\10\Debuggers\x64>gflags /i test.exe
Current Registry Settings for test.exe executable are: 00000010
htc - Enable heap tail checking
在下面的程序中,在使用 16 字节对齐的堆外分配了一个 4 字节整数。所以剩下的 12 个字节用标记字节填充。
int main()
{
int *p = new int{};
for (size_t i = 0; i < 16; ++i)
{
((char*)p)[i] = '0';
cout << ((char*)p)[i] << endl;
}
delete p;
cout << "After delete\n";
return 0;
}
根据 MSFT,这非常简单。
此标志在每个分配的末尾添加一个短模式。Windows 堆管理器在块被释放时检测到模式,如果块被修改,堆管理器会进入调试器。
然而,这并没有发生。未捕获缓冲区溢出,并且该过程成功完成。
循环前的内存布局,从分配的整数地址开始。ab ab ..
其余 12 个字节用正确的特定字节模式填充。
没有例外,没有调试器启动。之后的消息delete
也打印成功了。
注意: 如果我同时启用了 PageHeap ,那么同样的尾部缓冲区溢出问题(我确信它当然没有溢出到受 PageHeap 保护的下一页)就会被捕获。
这是堆管理器中的错误吗?我认为“启用堆尾检查”和 PageHeap 是两个独立的功能。