Вопрос по windows, c++, heap – Как отладить ошибки повреждения кучи?

155

Я отлаживаю (нативное) многопоточное приложение C ++ в Visual & # xA0; Studio & # xA0; 2008. В случайных, на первый взгляд, случаях я получаю "Windows сработала точка останова ..." ошибка с пометкой, что это может быть связано с повреждением в куче. Эти ошибки не всегда сразу приводят к сбою приложения, хотя, скорее всего, вскоре произойдет сбой приложения.

Большая проблема с этими ошибками заключается в том, что они всплывают только после фактического повреждения, что делает их очень сложными для отслеживания и отладки, особенно в многопоточных приложениях.

What sort of things can cause these errors?

How do I debug them?

Советы, инструменты, методы, просветления ... приветствуются.

Ваш Ответ

14   ответов
122

Проверка приложения в сочетании сИнструменты отладки для Windows это удивительная установка Вы можете получить как частьWindows Driver Kit или более легкий Windows SDK, (Узнал о Application Verifier при исследованиипредыдущий вопрос о проблеме кучи коррупции.) В прошлом я также использовал BoundsChecker и Insure ++ (упомянутые в других ответах), хотя я был удивлен, насколько много функциональности было в Application Verifier.

Электрический забор (он же "efence"),пооддержки, Valgrindи так далее, стоит упомянуть, но большинство из них гораздо проще запустить под * nix, чем Windows. Valgrind смехотворно гибок: я отлаживал программное обеспечение для больших серверов со многими проблемами кучи, используя его.

Когда все остальное терпит неудачу, вы можете предоставить своему собственному глобальному оператору перегрузки new / delete и malloc / calloc / realloc - как это будет немного различаться в зависимости от компилятора и платформы - и это будет немного вложено - но это может окупиться в долгосрочной перспективе. Список желаемых функций должен выглядеть знакомым по dmalloc и electricfence, и удивительно превосходной книгеНаписание твердого кода:

sentry values: allow a little more space before and after each alloc, respecting maximum alignment requirement; fill with magic numbers (helps catch buffer overflows and underflows, and the occasional "wild" pointer) alloc fill: fill new allocations with a magic non-0 value -- Visual C++ will already do this for you in Debug builds (helps catch use of uninitialized vars) free fill: fill in freed memory with a magic non-0 value, designed to trigger a segfault if it's dereferenced in most cases (helps catch dangling pointers) delayed free: don't return freed memory to the heap for a while, keep it free filled but not available (helps catch more dangling pointers, catches proximate double-frees) tracking: being able to record where an allocation was made can sometimes be useful

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

Если вы заинтересованы в большем количестве причин для перегрузки этих функций / операторов распределения, посмотрите намой ответ на "Любая причина перегрузить глобальный оператор new и удалить?"; Помимо бесстыдного саморекламы, в нем перечислены другие методы, которые помогают отслеживать ошибки повреждения кучи, а также другие применимые инструменты.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededmsdn.microsoft.com/en-us/library/ms220944(v=vs.90).aspxError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
0

ошибку в своем приложении. В моем конкретном случае ошибки в коде были:

Removing elements from an STL collection while iterating over it (I believe there are debug flags in Visual Studio to catch these things; I caught it during code review) This one is more complex, I'll divide it in steps: From a native C++ thread, call back into managed code In managed land, call Control.Invoke and dispose a managed object which wraps the native object to which the callback belongs. Since the object is still alive inside the native thread (it will remain blocked in the callback call until Control.Invoke ends). I should clarify that I use boost::thread, so I use a member function as the thread function. Solution: Use Control.BeginInvoke (my GUI is made with Winforms) instead so that the native thread can end before the object is destroyed (the callback's purpose is precisely notifying that the thread ended and the object can be destroyed).
8

Обнаружение доступа к освобожденной памяти это:

If you want to locate the error quickly, without checking every statement that accesses the memory block, you can set the memory pointer to an invalid value after freeing the block:

#ifdef _DEBUG // detect the access to freed memory
#undef free
#define free(p) _free_dbg(p, _NORMAL_BLOCK); *(int*)&p = 0x666;
#endif
3

существует высокая вероятность того, что вы столкнулись с гонками данных. Пожалуйста, проверьте: вы изменяете указатели общей памяти из разных потоков? Intel Thread Checker может помочь обнаружить такие проблемы в многопоточных программах.

12

мя выполнения, попробуйте добавить следующее в верхней частиmain() или эквивалент в Microsoft Visual Studio C ++

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_ALWAYS_DF );
8

Делать непослушные вещи с памятью, например запись после окончания буфера или запись в буфер после того, как он был освобожден обратно в кучу.

How do I debug them?

Используйте инструмент, который добавляет автоматическую проверку границ к вашему исполняемому файлу: то есть valgrind в Unix, или такой инструмент, как BoundsChecker (Wikipedia предлагает также Purify и Insure ++) в Windows.

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

Другим возможным средством отладки / инструментом может быть HeapAgent от MicroQuill.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
0

зможно, что-то было повреждено в файлах сборки, но в итоге я исправил это, сначала очистив проект, а затем восстановив его.

Так в дополнение к другим ответам дано:

What sort of things can cause these errors? Что-то повреждено в файле сборки.

How do I debug them? Очистка проекта и перестройка. Если это исправлено, вероятно, это проблема.

0

_CrtSetDbgFlag: _CRTDBG_CHECK_ALWAYS_DF или же_CRTDBG_CHECK_EVERY_16_DF.._CRTDBG_CHECK_EVERY_1024_DF.

4

ссылаетесь ли вы на динамическую или статическую библиотеку времени выполнения Си. Если ваши DLL-файлы связаны со статической библиотекой времени выполнения C, то DLL-файлы имеют отдельные кучи.

Следовательно, если бы вы создали объект в одной DLL и попытались освободить его в другой DLL, вы получили бы то же сообщение, которое вы видели выше. Эта проблема упоминается в другом вопросе о переполнении стека,Освобождение памяти, выделенной в другой DLL.

35

включив Page Heap для своего приложения. Для этого вам нужно использовать gflags.exe, который входит в составИнструменты отладки для Windows

Запустите Gflags.exe и в параметрах файла образа для вашего исполняемого файла отметьте & quot; Включить кучи страниц & quot; вариант.

Теперь перезапустите ваш exe-файл и подключитесь к отладчику. С включенным Page Heap приложение будет работать в режиме отладки при любом повреждении кучи.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
3

хожую ошибку, используя функции выделения в стиле Heap *.

Оказалось, что я по ошибке создавал кучу сHEAP_NO_SERIALIZE вариант. По сути, это делает функции Heap работающими без безопасности потоков. Это повышение производительности при правильном использовании, но никогда не должно использоваться, если вы используете HeapAlloc в многопоточной программе [1]. Я упоминаю об этом только потому, что в вашем посте упоминается о многопоточном приложении. Если вы где-нибудь используете HEAP_NO_SERIALIZE, удалите его, и это, вероятно, решит вашу проблему.

[1] В некоторых ситуациях это допустимо, но для этого требуется сериализовать вызовы к Heap *, что обычно не относится к многопоточным программам.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
1

подумайте о поиске вероятного виновника. Есть ли какой-либо компонент, который вы используете, возможно, не написанный вами, который, возможно, не был разработан и протестирован для работы в многопоточной среде? Или просто тот, который вы не делаетеknow бежал в такой среде.

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

5

который я нашел полезным и работал каждый раз, это проверка кода (с хорошими рецензентами кода).

Кроме проверки кода, я сначала попробуюКуча страниц, Page Heap занимает несколько секунд, чтобы установить, и если повезет, это может точно определить вашу проблему.

Если вам не повезло с Page Heap, скачайтеИнструменты отладки для Windows от Microsoft и научиться использовать WinDbg. Извините, я не могу оказать вам более конкретную помощь, но отладка многопоточного повреждения кучи - это больше искусство, чем наука. Google для "повреждения кучи WinDbg" и вы должны найти много статей на эту тему.

Похожие вопросы