PageHeap не показывает точное местоположение сбоя

#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, поэтому позволяет запускать гораздо более сложные сценарии.