Visual Studio — как найти источник ошибок повреждения кучи

Интересно, есть ли хороший способ найти исходный код, который вызывает ошибку повреждения кучи, учитывая адрес памяти данных, которые были записаны «вне» выделенного блока кучи в Visual Studio;

Выделенный (0008) свободный элемент списка 26F7F670 имеет неправильный размер (мертвый)

(Попытка записать некоторые заметки о том, как найти ошибки памяти)


person Danne    schedule 18.03.2010    source источник


Ответы (8)


Начните с установки windbg:

http://www.microsoft.com/whdc/Devtools/Debugging/default.mspx

Затем включите pageheap следующим образом:

gflags.exe –p /enable yourexecutable.exe /full

Это будет вставлять недоступную для записи страницу после каждого выделения кучи.

После запуска исполняемого файла из Windbg любые записи вне кучи теперь будут перехватываться этим отладчиком. Чтобы перевернуть кучи страниц, используйте это:

gflags.exe -p /disable yourexecutable.exe

Дополнительные сведения об использовании кучи страниц здесь.

person Andreas Brinck    schedule 19.03.2010
comment
Лучшее решение! Спас мою жизнь. Кроме того, можно напрямую открыть gflags.exe и использовать графический интерфейс. Перейдите в «Файл изображения», введите имя исполняемого файла и установите флажок «Включить кучу страниц». Подойдет любой отладчик. - person jiasli; 27.02.2015
comment
Большое спасибо. Мне потребовалось два дня, прежде чем я узнал об этой технике. Я просто проверяю Включить кучу страниц и использую отладчик Visual Studio, как обычно. И затем он сломается точно в той позиции кода, которая вызывает ошибку повреждения кучи. Моя ошибка связана с тем, что один поток постоянно передает данные, в то время как другой поток выделяет только память, достаточную для старых данных, чего недостаточно для хранения новых данных. - person khanhhh89; 23.03.2016
comment
Я пытаюсь установить эти инструменты отладки, но он просит меня удалить последнюю версию SDK. Пожалуйста, предложите - person Kinjan Bhavsar; 31.08.2016
comment
В моем случае это не помогает. При включении этого флага программа работает (проверено много раз). После того, как флаг выключен, программа аварийно завершает работу с ошибкой повреждения кучи. - person mistika; 02.11.2016
comment
для меня это /p не -p. Он не узнал -p. - person TankorSmash; 13.01.2017
comment
К сожалению, здесь тоже не повезло. программа по-прежнему падает, но она всегда находится в winnt.dll или какой-то аналогичной общей библиотеке Windows. - person T.S; 16.11.2017
comment
Будьте очень осторожны с этим!!! У меня была ситуация, когда я установил все gflags, но потом забыл их отключить. Мне потребовалась целая неделя, чтобы понять, что эти флаги вызывают следующую проблему. - person Dominique; 26.10.2018
comment
Я отлаживал свой код, но у сторонних dll были проблемы, поэтому вместо использования '/full' я использовал '/dll DLL[**,DLL]' и выбирал только свои dll. - person Robert Andrzejuk; 22.10.2019

Для Windows 10 вы можете включить < strong>PageHeap в инструменте GFlags, этот инструмент входит в состав Инструменты отладки для Windows.

Параметры кучи страниц в GFlags позволяют выбрать стандартную проверку кучи или проверку кучи на всю страницу. Остерегайтесь, полная проверка кучи использует полную страницу памяти для каждого выделения, поэтому это может привести к нехватке системной памяти.

Чтобы включить кучу страниц в GFlags:

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

Для проверки всех процессов используйте:

gflags /r +hpa

gflags /k +hpa

для одного процесса использования:

gflags /p /enable ImageFileName

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

gflags /i ImageFileName +hpa

gflags /p /enable ImageFileName /full

Две приведенные выше команды взаимозаменяемы.

Примечание. Все упомянутые выше параметры кучи страниц являются общесистемными параметрами, хранящимися в реестре (кроме /k), и действуют до тех пор, пока вы их не измените. Параметр /k — это параметр флага ядра, установленный для этого сеанса, который будет потерян при завершении работы Windows

Еще одним полезным инструментом является Средство проверки приложений, но оно не является частью средств отладки для Windows, а включено в Комплект разработки программного обеспечения для Windows (SDK).

person Merav Kochavi    schedule 17.01.2017

Может быть, вы можете попробовать средство проверки приложений Microsoft. Однажды он решил аналогичную проблему для меня, включив дополнительные проверки операций с кучей. На мой взгляд, случайность поврежденного адреса связана с тем, что куча может быть «незначительно» повреждена, и проблема не проявится, пока с кучей не произойдет что-то серьезное (например, массивное выделение/освобождение).

person Smithy    schedule 19.03.2010

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

person Timo Geusch    schedule 18.03.2010

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

person Community    schedule 14.02.2012
comment
Удачи с этим, Microsoft приложила все усилия, чтобы убедиться, что их команды обработки строк несовместимы с максимально возможным количеством стандартов. Если это очень просто, вы можете уйти с этим. - person Owl; 10.10.2017

дополнительная информация о Gflags и PageHeap (что очень помогло): http://msdn.microsoft.com/en-us/library/windows/hardware/ff549561%28v=vs.85%29.aspx

person NoAngel    schedule 26.05.2013

Я предполагаю C++ в качестве языка.

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

person Timores    schedule 18.03.2010
comment
Язык смешанный C/C++. Поврежденный адрес отличается в каждом сеансе отладки, поэтому я думаю, что невозможно использовать точку останова данных. - person Danne; 18.03.2010
comment
Вы, к сожалению, правы. В этих случаях мой подход заключается в том, чтобы #define free/delete ничего не значило. Если проблема исчезает, я #определяю malloc/new/free/delete в функцию, которая регистрирует каждый вызов, чтобы найти повторяющиеся удаления или удаления без распределения. - person Timores; 19.03.2010

Убедитесь, что все библиотеки, на которые вы ссылаетесь, скомпилированы в той же версии CLR, что и приложение, в котором вы работаете, — все в выпуске или все в отладке.

Когда вы компилируете в Debug и Release, вы на самом деле ориентируетесь на две разные версии библиотеки времени выполнения C. Эти версии совершенно разные, они используют разные стратегии выделения памяти и используют разные кучи. Но самое главное, что нужно знать, это то, что они НЕ совместимы друг с другом.

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

Если вы связываете свое приложение со смесью библиотек DLL, которые были созданы в Release и Debug, вы, скорее всего, в конечном итоге попытаетесь удалить объект в одной CLR, который был создан в другой. Это означает, что вы будете пытаться освободить больше или меньше памяти, чем было выделено для объекта, и это может привести к повреждению кучи.

Вы должны создать свое приложение, а также подключиться к библиотекам, которые созданы в той же конфигурации, либо Release, либо Debug.

Эта проблема может возникнуть, особенно в модулях, которые компилируются разными компиляторами.

Есть обходной путь, который я упомяну, но не рекомендую. Если по какой-то причине вам все еще нужно собирать в разных режимах, этот обходной путь позволит выделить и освободить всю память из одной и той же общей кучи. API GetProcessHeap позволит вам получить доступ к общей куче через различные модули. Используя HeapAlloc и HeapFree, вы можете выделять и освобождать память в общей куче. Примечание. HeapAlloc и HeapFree должны заменить все вызовы malloc и free в вашем приложении.

person Merav Kochavi    schedule 17.01.2017
comment
Я компилирую одну и ту же версию сторонних библиотек (например, OpenCV) как в отладке, так и в выпуске. Насколько я могу судить, это означает только то, что при отладке я не могу входить в какой-либо сторонний код, и что при отладке он также работает немного быстрее. Я ошибаюсь, как вы думаете? - person ILIA BROUDNO; 22.08.2017
comment
@ILIABROUDNO Обычно распространяемые сторонние библиотеки распространяют библиотеку выпуска, которую другие могут использовать в режиме выпуска или отладки. Они делают это, создавая свои библиотеки DLL, чтобы включить свою копию библиотеки времени выполнения C, наряду с этим, они следят за тем, чтобы ресурсы CRT, такие как куча, не использовались совместно с границами библиотеки, чтобы гарантировать, что динамически выделяемая память будет освобождена в том же сторону границы. В заключение, если сторонние библиотеки, на которые вы ссылаетесь, сделали это, у вас не должно возникнуть проблем с их использованием в выпуске, а также в отладке. - person Merav Kochavi; 22.08.2017
comment
@ILIABROUDNO, если это было полезно, пожалуйста, +1 :) - person Merav Kochavi; 22.08.2017