Повреждение кучи при отсечке отложенной свободной очереди - PullRequest
4 голосов
/ 24 июня 2011

В настоящее время я пытаюсь отследить источник повреждения кучи в нашей кодовой базе, которая не отображается, когда включено отслеживание кучи полной страницы (поэтому только обычное отслеживание страницы).

IЯ использую Application Verifier для устранения повреждения и получения не очень полезного кода остановки 00000008:

APPLICATION_VERIFIER_HEAPS_CORRUPTED_HEAP_BLOCK (8)
Поврежденный блок кучи.
Это блокгенерируется общая ошибка, если повреждение в блоке кучи нельзя поместить в более конкретную категорию.

======================================
ОСТАНОВКА ПРОВЕРКИ 00000008: pid 0xD30: поврежденный блок кучи.

00000000: дескриптор кучи, используемый в вызове.
0861C000: блок кучиучаствует в операции.
0000043C: размер блока кучи.
00000000: зарезервирован

=============================================

Мне пришлось сократить отчет, чтобы защитить невинных, но потерпите меня.В стеке вызовов показано:

1000c540 00000008 00000000 vrfcore!VerifierStopMessageEx+0x543
00000008 7c969624 00000000 vrfcore!VfCoreRedirectedStopMessage+0x81
00000000 00000009 0861c000 ntdll!RtlpDphReportCorruptedBlock+0x101
04a680ee 01001002 03ce1000 ntdll!RtlpDphTrimDelayedFreeQueue+0x84
03ce1000 01001002 04a680ee ntdll!RtlpDphNormalHeapFree+0xc0
03ce0000 01001002 137a0040 ntdll!RtlpDebugPageHeapFree+0x79
03ce0000 01001002 137a0040 ntdll!RtlDebugFreeHeap+0x2c
03ce0000 01001002 137a0040 ntdll!RtlFreeHeapSlowly+0x37
03ce0000 00000000 137a0040 ntdll!RtlFreeHeap+0xf9
137a0040 137a0040 030dfe61 msvcrt!free+0xc3

Первоначально я сосредоточил свое внимание на вызове free(), предполагая, что память, которую я пытался освободить, была виновником повреждения кучи.Это все еще может иметь место, но я больше не убежден.Наблюдая за 0x137a0040, пока я выполняю вызов удаления, кажется, память освобождается при вызове RtlpDphNormalHeapFree().Я предполагаю, что она освобождается должным образом, поскольку память от 0x137a0040 до ее верхней границы примерно через 76 МБ состоит исключительно из f0, определяемой здесь как свободная память.

Поэтому мое внимание переключается на вызов непосредственно перед вызовом на RtlpDphReportCorruptedBlock(), RtlpDphTrimDelayedFreeQueue().Аргументы, переданные в RtlpDphReportCorruptedBlock(), указали бы мне (только предположение, я не могу найти никаких подсказок относительно объявлений этих функций), что это поврежденный блок.Исследование этого блока показывает следующее:

0861c000 f0 f0 f0 f0 4f f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 f0 ....O..............

Почему этот 5-й байт 4f, а все остальные f0 (уже освобождены)?Что делает RtlpDphTrimDelayedFreeQueue()?Является ли проблемой (если это проблема) то, что эта функция пытается освободить то, что явно уже освободило память, или эта функция ожидает, что эта память уже свободна, и теряет график, когда встречает этот 5-й байт?

(5-й байт является единственным нечетным, 0x0861c000 до 0x0861c43c равен f0)

К сожалению, хотя я могу воспроизвести повреждение кучи в 100% случаев, адрескажется, меняется каждый раз, когда я помещаю на него точку останова данных.

Я работаю на Windows XP SP3, и приложение написано на VC ++ 6

Есть идеи?

Ответы [ 3 ]

1 голос
/ 24 июня 2011

Это говорит о том, что вы изменили блок после того, как освободили его - возможно, из другого потока или потому, что что-то еще имеет указатель на него.(Когда вы освобождаете его, среда выполнения устанавливает его на все F0, некоторое время удерживает его, затем проверяет, что это все еще F0; это не так, поэтому он должен быть изменен после освобождения.)

Если искажение находится в постоянном смещении в блоке, вы можете установить точку останова в этом месте, изменив в точке вызова значение free().

1 голос
/ 24 июня 2011

C или C ++?

Если это C ++, возможно, вы можете переопределить new & delete и найти его самостоятельно.Просто никогда не освобождай память, положи в свой банк.Выделите память с полями ядов до и после и поместите яд в память, когда она находится в вашем банке, и постоянно проверяйте этот яд.

Если это C, вы можете сделать что-то подобное с #define malloc.Я также хотел бы выяснить, позволяет ли VC6 использовать обработчики вместо malloc и free.

0 голосов
/ 24 июня 2011

Похоже, что вы имеете дело с повреждением кучи, и почти наверняка это повреждение произошло за некоторое время до фактического сбоя в стеке вызовов, который вы опубликовали. Функции Rtl...() не вызывают повреждение, они просто вынуждают его обнаруживать.

В этом сообщении MSDN описывается проблема, аналогичная вашей, и несколько способов ее устранения. Существует также эта статья MS-KB , которая описывает повреждение кучи в VC6. В обеих этих ссылках (и нескольких других, которые я обнаружил) упоминается многопоточность, которая позволяет проверить, используете ли вы ее.

Существует также приложение PageHeap от MS, хотя оно может делать то же самое, что и Application Verifier.

...