#c #memory-management #windbg #pageheap
#c #управление памятью #windbg #pageheap
Вопрос:
Я использую PageHeap для выявления повреждения кучи. У моего приложения повреждение кучи. Но приложение прерывается (из-за сбоя), когда оно создает объект stl для строки, переданной методу. Я не вижу никаких видимых проблем с памятью рядом с местом сбоя. Я включил полную кучу страниц для обнаружения повреждения кучи и / RTCs для обнаружения повреждения стека.
Что я должен сделать, чтобы прервать работу в точном месте, где происходит повреждение кучи?
Комментарии:
1. что заставило вас подумать, что у вас повреждение кучи? Если включение кучи страниц не привело к сбою в том месте, где вы подозреваете, что куча была повреждена, возможно, у вас другая проблема. Используете ли вы catch (…) в своем приложении, это фактически зафиксировало бы нарушения доступа, чтобы ваше приложение на самом деле не зависало в этом месте. После того, как вы включили кучу страниц, использовали ли вы отладчик для запуска приложения? (VS в среде разработки или adplus в производственной среде)
2. @DXM: Я начал часто сталкиваться с проблемой после включения опции / RTCs. Я отключил все ctach (…). Я использую среду VS dev для отладки
Ответ №1:
Включение ПОЛНОГО pageheap может увеличить шансы отладчика обнаружить повреждение кучи, когда это происходит:
gflags /p /enable /full <processname>
Кроме того, если вы можете узнать, какой адрес перезаписывается, вы можете установить точку останова при доступе к памяти в windbg. Не уверен, что у отладчика VS есть такая же функция.
Ответ №2:
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 приложение, вероятно, просто столкнулось бы с реализацией кучи, пытающейся использовать недопустимый указатель.)
Таким образом, Pageheap не дает вам 100% гарантии обнаружить повреждение точно в тот момент, когда оно происходит. Вам нужны такие инструменты, как Purify или Valgrind, которые отслеживают каждый доступ к памяти.
Не поймите меня неправильно, я думаю, что Pageheap по-прежнему очень полезен. Это приводит к гораздо меньшему снижению производительности по сравнению с упомянутыми Purify и Valgrind, поэтому позволяет запускать гораздо более сложные сценарии.