Page Heap не записывает полезную информацию стека?
Я пытаюсь протестировать сценарий сбоя (в изолированном тестовом приложении) с нормальной кучей страниц (не полностью).
Я установил флаги с
gflags /p /enable Test.exe
и я перезаписываю целочисленный буфер одним элементом
...
const size_t s = 100;
vector<int> v1(s, 0);
int* v1_base = &v1[0];
write_to_memory_int(v1_base, s+1);
...
и действительно, когда блок освобождается в векторах, я получаю перерыв. Callstack для перерыва сообщается правильно:
0:005> kp
*** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr
0785faa4 11229df2 verifier!VerifierStopMessage+0x1f8
0785fb08 1122a22a verifier!AVrfpDphReportCorruptedBlock+0x1c2
0785fb64 1122a742 verifier!AVrfpDphCheckNormalHeapBlock+0x11a
0785fb84 112290d3 verifier!AVrfpDphNormalHeapFree+0x22
0785fba8 77951564 verifier!AVrfDebugPageHeapFree+0xe3
0785fbf0 7790ac29 ntdll!RtlDebugFreeHeap+0x2f
0785fce4 778b34a2 ntdll!RtlpFreeHeap+0x5d
0785fd04 750c14dd ntdll!RtlFreeHeap+0x142
0785fd18 71fc4c39 kernel32!HeapFree+0x14
0785fd64 00404b0a msvcr80!free(void * pBlock = 0x0726f7b8)+0xcd [f:\dd\vctools\crt_bld\self_x86\crt\src\free.c @ 110]
0785fd90 00402ac7 Test!std::vector<int,std::allocator<int> >::_Tidy
...
Однако, когда я смотрю на ошибочное распределение, я получаю только это:
0:005> !heap -p -a 0x0726f7b8
address 0726f7b8 found in
_HEAP @ 30000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
0726f790 0039 0000 [00] 0726f7b8 00190 - (busy)
1122a6a7 verifier!AVrfpDphNormalHeapAllocate+0x000000d7
11228f6e verifier!AVrfDebugPageHeapAllocate+0x0000030e
77950d96 ntdll!RtlDebugAllocateHeap+0x00000030
7790af0d ntdll!RtlpAllocateHeap+0x000000c4
778b3cfe ntdll!RtlAllocateHeap+0x0000023a
то есть трассировка стека выделения, но она останавливается на RtlAllocateHeap
что, очевидно, совершенно бесполезно.
Глядя на трассировку стека в памяти:
dt _DPH_BLOCK_INFORMATION ....-0x20
=>
0:005> dds 0x03e556f4
03e556f4 00000000
03e556f8 00002050
03e556fc 00050000
03e55700 1122a6a7 verifier!AVrfpDphNormalHeapAllocate+0xd7
03e55704 11228f6e verifier!AVrfDebugPageHeapAllocate+0x30e
03e55708 77950d96 ntdll!RtlDebugAllocateHeap+0x30
03e5570c 7790af0d ntdll!RtlpAllocateHeap+0xc4
03e55710 778b3cfe ntdll!RtlAllocateHeap+0x23a
03e55714 00000000
03e55718 00003001
03e5571c 0004005e
Похоже, что на самом деле больше ничего не записано.
Как я могу исправить Page Heap для записи полезных трассировок стека?
Обратите внимание, что тестовый проект не скомпилирован с FPO (/Oy), и я не ожидал, что RtlAllocateHeap
быть затронутым FPO?
Обновление: я проверил FPO-необходимость рассматриваемого вызова, войдя в выделение вручную (см. Ниже), и оказалось, что оба malloc
так же как op new
для библиотек времени выполнения VC80(VS2005) включена некоторая форма FPO... так что, возможно, это испортило трассировку стека для стековой базы данных кучи страниц.
0:004> kv
ChildEBP RetAddr Args to Child
077efa7c 77c8af0d 05290000 01001002 00000190 ntdll!RtlDebugAllocateHeap+0x16 (FPO: [Non-Fpo])
077efb60 77c33cfe 00000190 00000000 00000000 ntdll!RtlpAllocateHeap+0xc4 (FPO: [Non-Fpo])
077efbe4 72344d83 05290000 01001002 00000190 ntdll!RtlAllocateHeap+0x23a (FPO: [Non-Fpo])
077efc04 62f595ee 00000190 00000000 00000000 MSVCR80!malloc+0x7a (FPO: [1,0,0]) (CONV: cdecl)
077efc1c 00406a44 00000190 ebecf74f 00000001 MFC80U!operator new+0x2f (FPO: [Uses EBP] [1,0,0]) (CONV: cdecl)
077efc48 00405479 00000064 00000000 3fffffff Test!std::_Allocate<ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t> > > >+0x84 (FPO: [Non-Fpo]) (CONV: cdecl)
077efcb8 004049f4 00000064 ebecf68f 00000000 Test!std::vector<unsigned int,std::allocator<unsigned int> >::_Buy+0x69 (FPO: [Non-Fpo]) (CONV: thiscall)
077efd88 00402a4f 00000064 077efdc0 ebecf44b Test!std::vector<int,std::allocator<int> >::_Construct_n+0x44 (FPO: [Non-Fpo]) (CONV: thiscall)
077eff4c 72342848 00000000 ebec8474 00000000 Test!crashFN+0x35f (FPO: [Non-Fpo]) (CONV: cdecl)
077eff84 723428c8 75da33aa 072ab3d8 077effd4 MSVCR80!_callthreadstart+0x1b (FPO: [Non-Fpo]) (CONV: cdecl)
077eff88 75da33aa 072ab3d8 077effd4 77c39f72 MSVCR80!_threadstart+0x5a (FPO: [1,0,0]) (CONV: stdcall)
077eff94 77c39f72 072ab3d8 70fca8b2 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
077effd4 77c39f45 7234286e 072ab3d8 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
077effec 00000000 7234286e 072ab3d8 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])
1 ответ
Спасибо @Marc Sherman за указание в комментариях, что я должен проверить реальную трассировку стека выделения.
Как уже было отредактировано в вопросе, здесь проблема с VC80(VS2005), поскольку в CRT включена функция FPO, как видно из трассировки стека:
MSVCR80!malloc+0x7a (FPO: [1,0,0]) (CONV: cdecl)
MFC80U!operator new+0x2f (FPO: [Uses EBP] [1,0,0]) (CONV: cdecl)
Теперь, имея привязку к поиску, мы находим следующее:
Почему каждый след кучи в UMDH застревает в "malloc"?
Добавим несколько цитат:
В частности, может показаться, что стандартная реализация malloc на CRT статической ссылки в Visual C++ 2005 не только не использует указатель фрейма, но и перехватывает ebp как регистр нуля...
Что все это значит? Ну, все, что использует malloc, созданное с помощью Visual C++ 2005, не может быть диагностировано с помощью UMDH или чего-либо еще, что основано на трассировке стека на основе ebp, по крайней мере, не на сборках x86.
Есть также ответ в комментариях, которые получили хорошую информацию:
Марк Робертс [MSFT] говорит: 25 февраля 2008 в 15:03
Привет,
Включение FPO для CRT 8.0 не было преднамеренным. В Visual Studio 2008 CRT (9.0) НЕ включена FPO, и UMDH должен работать нормально.
Для 8.0 альтернативой UMDH будет использование LeakDiag. LeakDiag фактически использует инструмент распределения памяти для получения трассировки стека. Это делает его более универсальным, чем UMDH, поскольку он может подключать несколько разных типов распределителей с разной степенью детализации (начиная от среды выполнения c и заканчивая необработанными выделениями виртуальной памяти).
По умолчанию LeakDiag просто обходит базовые указатели стека, но его можно изменить, чтобы использовать Dbghlp StackWalkAPI для разрешения данных FPO. Это даст полные стеки, хотя снижение производительности будет выше. С другой стороны, вы можете настроить поведение при стэке, чтобы идти только на определенную глубину и т. Д., Чтобы минимизировать штраф перфорации.
Пожалуйста, найдите LeakDiag здесь: ftp://ftp.microsoft.com/PSS/Tools/Developer%20Support%20Tools/LeakDiag/leakdiag125.msi