我在Visual Studio 2017下调试一个多线程的C++应用,问题类型可以用下面的代码示例重现
int* i = new int();
*i = 4;
int* j = i;
delete i;
//perhaps some code or time passes
*j = 5;//write to freed momory = possible heap corruption!!
我已经使用 built in heap checker 来查找标志问题的类型:
_CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_DELAY_FREE_MEM_DF )
然后使用
_ASSERTE(_CrtCheckMemory());
尝试缩小范围 - 但只能得出结论它在另一个线程中。在检测到损坏时查看其他线程似乎只是在做“正常”的事情,而当时不在应用程序的代码中。报告看起来像这样:
HEAP CORRUPTION DETECTED: on top of Free block at 0x00000214938B88D0.
CRT detected that the application wrote to a heap buffer that was freed.
DAMAGED located at 0x00000214938B88D0 is 120 bytes long.
Debug Assertion Failed!
每次 120 字节 - 但地址各不相同。 (检测的方式是检查堆时0xdddddddd模式已被覆盖)
找到分配或找到有问题的写入都会有所帮助。
我尝试使用 'gflags.exe' ,但我无法找到这种类型的损坏(据我所知,它主要用于查找缓冲区溢出),而且我以前没有使用此工具的经验。
如果我能从地址中找到“唯一分配号”,那也可能会有所帮助。
最佳答案
这是我用来追踪它的代码。 执行摘要: 它使虚拟内存中的页面未提交而不是完全释放。这意味着尝试使用此类页面将失败。
DWORD PageSize = 0;
namespace {
inline void SetPageSize()
{
if (!PageSize)
{
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
PageSize = sysInfo.dwPageSize;
}
}
void* alloc_impl(size_t nSize) {
SetPageSize();
size_t Extra = nSize % PageSize;
if (Extra != 0 || nSize == 0) {
nSize = nSize + (PageSize - Extra);
}
void* res = VirtualAlloc(0, nSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!res) {
DWORD errorMessageID = ::GetLastError();
LPSTR messageBuffer = nullptr;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
throw std::bad_alloc{};
}
if (reinterpret_cast<size_t>(res) % PageSize != 0) {
throw std::bad_alloc{};
}
return res;
}
void dealloc_impl(void* pPtr) {
if (pPtr == nullptr) {
return;
}
VirtualFree(pPtr, 0, MEM_DECOMMIT);
}
}
void* operator new (size_t nSize)
{
return alloc_impl(nSize);
}
void operator delete (void* pPtr)
{
dealloc_impl(pPtr);
}
void *operator new[](std::size_t nSize) throw(std::bad_alloc)
{
return alloc_impl(nSize);
}
void operator delete[](void *pPtr) throw()
{
dealloc_impl(pPtr);
}
关于c++ - 如何找到对已释放内存的写入(堆损坏)?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55523264/