PageHeap не показывает точное место сбоя
Я использую PageHeap для выявления повреждения кучи. Мое приложение имеет кучу повреждений. Но приложение разрывается (из-за сбоя), когда оно создает объект stl для строки, переданной методу. Я не вижу видимых проблем с памятью рядом с местом сбоя. Я включил полную страницу кучи для обнаружения повреждения кучи и /RTC для выявления повреждения стека.
Что я должен сделать, чтобы сломаться в точном месте, где происходит повреждение кучи?
2 ответа
Включение FULL pageheap может увеличить вероятность того, что отладчик обнаружит повреждение кучи по мере его возникновения:
gflags /p /enable /full <processname>
Кроме того, если вы можете узнать, какой адрес перезаписывается, вы можете установить точку останова на доступ к памяти в windbg. Не уверен, что отладчик VS имеет такую же функцию.
Pageheap не всегда обнаруживает повреждение кучи именно в тот момент, когда оно происходит.
Pageheap вставляет неверную страницу сразу после выделения. Поэтому, когда вы переполняете выделенный блок, вы получаете AV. Но есть и другие возможные случаи. Одним из примеров является запись непосредственно перед распределенной структурой данных заголовка блока кучи. Заголовок блока кучи является допустимой доступной для записи памятью (скорее всего, на той же странице, что и выделенный блок). Рассмотрим следующий пример:
#include <stdlib.h>
int
main()
{
void* block = malloc(100);
int* intPtr = (int*)block;
*(intPtr-1) = 0x12345; // no crash
free(block); // crash
return 0;
}
Таким образом, написание некоторого мусора непосредственно перед тем, как выделенный блок пройдет нормально. При включенном Pageheap пример разрывается внутри free()
вызов. Вот стек вызовов:
verifier.dll!_VerifierStopMessage@40() + 0x206 bytes
verifier.dll!_AVrfpDphReportCorruptedBlock@16() + 0x239 bytes
verifier.dll!_AVrfpDphCheckNormalHeapBlock@16() + 0x11a bytes
verifier.dll!_AVrfpDphNormalHeapFree@16() + 0x22 bytes
verifier.dll!_AVrfDebugPageHeapFree@12() + 0xe3 bytes
ntdll.dll!_RtlDebugFreeHeap@12() + 0x2f bytes
ntdll.dll!@RtlpFreeHeap@16() + 0x36919 bytes
ntdll.dll!_RtlFreeHeap@12() + 0x722 bytes
heapripper.exe!free(void * pBlock=0x0603bf98) Line 110 C
> heapripper.exe!main() Line 11 + 0x9 bytes C++
heapripper.exe!__tmainCRTStartup() Line 266 + 0x12 bytes C
kernel32.dll!@BaseThreadInitThunk@12() + 0xe bytes
ntdll.dll!___RtlUserThreadStart@8() + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x1b bytes
Pageheap включает строгие проверки согласованности кучи, но проверки не включаются до тех пор, пока не будет вызван какой-либо другой API кучи. Процедуры проверки видны в стеке. (Без Pageheap приложение, вероятно, просто AV в реализации кучи пытается использовать недопустимый указатель.)
Таким образом, Pageheap не дает вам 100% гарантии отловить коррупцию именно в тот момент, когда она происходит. Вам нужны такие инструменты, как Purify или Valgrind, которые отслеживают каждый доступ к памяти.
Не поймите меня неправильно, я думаю, что Pageheap все еще очень полезен. Это вызывает намного меньшее снижение производительности по сравнению с упомянутыми Purify и Valgrind, поэтому позволяет запускать гораздо более сложные сценарии.