возможно повреждение кучи (win 32, native c ++) - PullRequest
3 голосов
/ 10 сентября 2010

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

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

Цикл состоит из обхода двойного связанного списка, который стал циклическим. Существуют признаки повреждения памяти, поскольку многие члены данных имеют странные значения, например, отсутствие соответствующего перечислителя, значения в 0000FFFF или сам связанный список имеет размер 300 миллионов+, что не является нормальным.

Единственная другая информация, которую я могу получить из дампов, - это то, что операция чтения сокета завершилась неудачно с чтением 0 данных. Это вызывает обход списка (теперь циклического).

У меня есть несколько дампов, висящих в одном и том же бесконечном цикле. Я пытался получить трассировку стека выделения, но! Куча -p -a дает мне "Ошибка ReadMemory для адреса eeddccee Используйте `! Address eeddccee ', чтобы проверить правильность адреса." для всех адресов, которые я пытаюсь.

В настоящее время я смотрю на исправление предупреждений L4 (за исключением того, что я не знаю, что может быть связано с этим, у меня есть куча C4100, C4511, C4512, которые я не знаю, как исправить; я по большей части чинит несложно, как C4244). DebugDiag не нашел ничего, кроме как дать мне «Этот поток не полностью решен и может быть, а может и не быть проблемой. Может потребоваться дальнейший анализ этих потоков». на одной нити.

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

Это действительно повреждение памяти? Почему он каждый раз висит в одной и той же структуре? Как я могу найти причину?

Ответы [ 4 ]

1 голос
/ 10 сентября 2010

Если это какая-то куча, то Application Verifier может помочь обнаружить это в вашей собственной среде.

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

Если Application Verifier или какой-либо другой инструмент не легко обнаружит проблему, то это может привести к выводу того, что могло привести кк проблеме .Сосредоточьтесь на конкретной проблеме, такой как круговой список.Что может вызвать это?Очевидные места для поиска - все фрагменты кода, которые касаются списка (возможно, что случайная неправильная запись в память может вызвать его, но чаще преступник оказывается ближе к месту преступления).

Если доступ к списку возможен только с помощью четко определенных методов, ваша работа станет проще.Если через глобальный указатель каждый может дотронуться, то сложнее, но все же можно проверить, просматриваете ли вы все ссылки (это может сделать любой хороший редактор).Если вы обнаружите, например, случай ошибки, который, возможно, не очень хорошо очищается и правильно заполняет обратную ссылку, то вы можете оказаться на полпути.Затем вы работаете в обратном направлении оттуда.Что может вызвать эту конкретную ошибку?И так далее.Вывод «возможной» цепочки событий, которая может привести к определенной ситуации, часто может решить проблему, подобную этой (и может заставить вас почувствовать себя волшебником в процессе, особенно если вы обнаружите чью-то ошибку).

1 голос
/ 10 сентября 2010

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

Ошибка чтения сокета с 0 данными может означать, что сокет закрыт. Возможно, у вас есть проблема синхронизации, когда логика закрытия сокета приводит к одновременному доступу к некоторой общей структуре данных, которая не заблокирована должным образом. Внимательно посмотрите на код сокета, чтобы убедиться в правильности и герметичности блокировки. Убедитесь, что все возможные коды ошибок правильно обрабатываются в ваших вызовах API сокетов (Winsock, предположительно?). Вы можете быть уверены, что даже малейшее окно для одновременного доступа к контейнеру или «ошибки не могут быть» в конечном итоге попадут в вашу производственную среду. Я знаю, вы сказали, что приложение является однопоточным, но у Windows есть забавная привычка давать вам дополнительные потоки, которые вы сами не запускали, например, если вы используете службы DLL, которые сами запускают новые потоки.

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

Другим вариантом может быть установка Process Dumper на неисправном компьютере и указание ему выгрузить полный образ памяти (отлаживаемый в соответствии со стандартным файлом Windbg DMP) при нарушении прав доступа и выходе из процесса. Это может предоставить лучшую информацию, чем минимальная отладка. Если ваш клиент сотрудничает, он может дать указание создать дамп при следующей проблеме. Это самый близкий способ получить доступ к оперативной отладке, не находясь на компьютере или не имея удаленного доступа к нему.

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

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

0 голосов
/ 04 октября 2017

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

0 голосов
/ 10 сентября 2010

Это может быть что угодно.

Если это повреждение кучи, попробуйте вставить проверки кучи в код в стратегических местах.Убедитесь, что ваши двоичные файлы скомпилированы с проверками времени выполнения, которые предлагает компилятор Visual C ++.Если возможно, получите тестовый пример от своих пользователей.Если это невозможно, попытайтесь заставить их выполнить отладку двоичного файла и / или отладить работающее приложение.Исправление предупреждения - хорошая идея, хотя я считаю, что большинство предупреждений 4-го уровня VC менее чем полезно.Обильно посыпьте свой код проверками assert (like).Убедитесь, что все ваши предварительные условия и пост-условия проверены.Убедитесь, что вы действительно обрабатываете каждое возвращаемое значение всех вызовов функций.Также избегайте любых сомнительных практик в коде, таких как использование приведения в стиле C и тип punning.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...