Application Verifier в сочетании с инструментами отладки для Windows - удивительная установка. Вы можете получить как часть комплекта драйверов Windows, так и более легкий пакет Windows SDK . (Узнал о Application Verifier при исследовании более раннего вопроса о проблеме повреждения кучи .) Я также использовал BoundsChecker и Insure ++ (упомянутые в других ответах) и в прошлом, хотя я был удивлен, насколько много функциональности было в Application Verifier.
Стоит упомянуть Electric Fence (он же «efence»), dmalloc , valgrind и т. Д., Но большинство из них гораздо проще запустить под * nix, чем Windows. Valgrind смехотворно гибок: я отлаживал программное обеспечение для больших серверов со многими проблемами кучи, используя его.
Когда все остальное терпит неудачу, вы можете предоставить своему собственному глобальному оператору перегрузки new / delete и malloc / calloc / realloc - как это будет немного различаться в зависимости от компилятора и платформы - и это будет немного вложено - но это может окупиться в долгосрочной перспективе. Список желаемых функций должен выглядеть знакомым по dmalloc и electricfence, а также поразительно превосходной книге « Написание твердого кода» :
- значения Sentry : оставьте немного больше места до и после каждого размещения, соблюдая требования максимального выравнивания; заполнить магическими числами (помогает улавливать переполнения и переполнения буфера и случайный «дикий» указатель)
- alloc fill : заполнять новые выделения магическим ненулевым значением - Visual C ++ уже сделает это за вас в сборках отладки (помогает отловить использование неинициализированных переменных)
- free fill : заполнить освобожденную память магическим значением, отличным от 0, предназначенным для запуска сегментарного сбоя, если в большинстве случаев он разыменовывается (помогает отлавливать висячие указатели)
- освобождение с задержкой : не возвращать освобожденную память в кучу на некоторое время, держать ее свободной, заполненной, но недоступной (помогает отлавливать больше висячих указателей, ловит близкие двойные освобождения)
- отслеживание : возможность записать, где было сделано выделение, иногда может быть полезным
Обратите внимание, что в нашей локальной системе доморощения (для встроенной цели) мы держим отслеживание отдельно от большинства других вещей, потому что время выполнения намного выше.
Если вас интересуют другие причины перегрузки этих функций / операторов распределения, взгляните на мой ответ: «Есть ли причина перегрузить глобальный оператор new и delete?» ; Помимо бесстыдного саморекламы, в нем перечислены другие методы, которые помогают отслеживать ошибки повреждения кучи, а также другие применимые инструменты.
Поскольку я продолжаю находить здесь свой собственный ответ при поиске значений alloc / free / fence, которые использует MS, вот еще один ответ, который охватывает значения заполнения dbgheap от Microsoft .
Вы можете обнаружить много проблем с повреждением кучи, включив Page Heap для своего приложения. Для этого вам нужно использовать gflags.exe, который входит в состав средств отладки для Windows
Запустите Gflags.exe и в параметрах файла образа для вашего исполняемого файла установите флажок «Включить кучи страницы».
Теперь перезапустите ваш exe-файл и подключитесь к отладчику. С включенным Page Heap приложение будет работать в режиме отладки при любом повреждении кучи.
источник
Чтобы действительно замедлить работу и выполнить много проверок во время выполнения, попробуйте добавить следующее в верхней части своего
main()
или аналогичного в Microsoft Visual Studio C ++источник
Очень актуальной статьей является Отладка повреждения кучи с помощью Application Verifier и Debugdiag .
источник
Делать непослушные вещи с памятью, например, запись после окончания буфера или запись в буфер после его освобождения обратно в кучу.
Используйте инструмент, который добавляет автоматическую проверку границ к вашему исполняемому файлу: например, valgrind в Unix, или такой инструмент, как BoundsChecker (Wikipedia предлагает также Purify и Insure ++) в Windows.
Имейте в виду, что это замедлит работу вашего приложения, поэтому они могут оказаться непригодными для использования, если ваше приложение работает в режиме реального времени.
Другим возможным средством отладки / инструментом может быть HeapAgent от MicroQuill.
источник
Один быстрый совет, который я получил от Обнаружения доступа к освобожденной памяти, - это:
источник
Лучший инструмент, который я нашел полезным и работал каждый раз, это проверка кода (с хорошими рецензентами кода).
Помимо проверки кода, я бы сначала попробовал Page Heap . Page Heap настраивается за несколько секунд, и, если повезет, он может точно определить вашу проблему.
Если вам не повезло с Page Heap, загрузите средства отладки для Windows от Microsoft и научитесь использовать WinDbg. Извините, что не смогу дать вам более конкретной помощи, но отладка многопоточного повреждения кучи - это больше искусство, чем наука. Google для "Повреждение кучи WinDbg", и вы должны найти много статей на эту тему.
источник
Вы также можете проверить, ссылаетесь ли вы на динамическую или статическую библиотеку времени выполнения C. Если ваши DLL-файлы связаны со статической библиотекой времени выполнения C, то DLL-файлы имеют отдельные кучи.
Следовательно, если вы создадите объект в одной DLL и попытаетесь освободить его в другой DLL, вы получите то же сообщение, которое вы видели выше. Эта проблема упоминается в другом вопросе переполнения стека: освобождение памяти, выделенной в другой DLL .
источник
Какой тип функций распределения вы используете? Недавно я обнаружил похожую ошибку, используя функции выделения в стиле Heap *.
Оказалось, что я по ошибке создавал кучу с
HEAP_NO_SERIALIZE
опцией. Это, по сути, заставляет функции Heap работать без безопасности потоков. Это повышение производительности при правильном использовании, но его никогда не следует использовать, если вы используете HeapAlloc в многопоточной программе [1]. Я упоминаю об этом только потому, что в вашем посте упоминается о многопоточном приложении. Если вы где-нибудь используете HEAP_NO_SERIALIZE, удалите его, и это, вероятно, решит вашу проблему.[1] В определенных ситуациях это допустимо, но для этого требуется сериализовать вызовы к Heap *, что обычно не относится к многопоточным программам.
источник
Если эти ошибки происходят случайным образом, существует высокая вероятность того, что вы столкнулись с гонками данных. Пожалуйста, проверьте: вы изменяете указатели общей памяти из разных потоков? Intel Thread Checker может помочь обнаружить такие проблемы в многопоточных программах.
источник
В дополнение к поиску инструментов, подумайте о поиске вероятного виновника. Есть ли какой-то компонент, который вы используете, возможно, не написанный вами, который, возможно, не был разработан и протестирован для работы в многопоточной среде? Или просто тот, который вы не знаете , работал в такой среде.
В прошлый раз, когда это случилось со мной, это был нативный пакет, который годами успешно использовался для пакетных заданий. Но впервые в этой компании он использовался из веб-службы .NET (которая является многопоточной). Вот и все - они солгали, что код безопасен для потоков.
источник
Вы можете использовать макросы VC CRT Heap-Check для _CrtSetDbgFlag : _CRTDBG_CHECK_ALWAYS_DF или _CRTDBG_CHECK_EVERY_16_DF .. _CRTDBG_CHECK_EVERY_1024_DF .
источник
Я хотел бы добавить свой опыт. В последние несколько дней я решил эту ошибку в своем приложении. В моем конкретном случае ошибки в коде были:
Control.Invoke
и располагайте управляемым объектом, который обертывает собственный объект, которому принадлежит обратный вызов.Control.Invoke
конца). Я должен уточнить, что я используюboost::thread
, поэтому я использую функцию-член в качестве функции потока.Control.BeginInvoke
вместо этого (мой GUI сделан с Winforms), чтобы собственный поток мог завершиться до того, как объект будет уничтожен (цель обратного вызова - точное уведомление о том, что поток завершился и объект может быть уничтожен).источник
У меня была похожая проблема - и она появилась совершенно случайно. Возможно, что-то было повреждено в файлах сборки, но в итоге я исправил это, сначала очистив проект, а затем восстановив его.
Итак, в дополнение к другим ответам даны:
Какие вещи могут вызвать эти ошибки? Что-то повреждено в файле сборки.
Как мне их отладить? Очистка проекта и перестройка. Если это исправлено, скорее всего, это проблема.
источник