2010-09-10 5 views
3

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

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

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

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

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

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

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

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

+1

Вы выполняете обработку исключений? Например, вы ловите исключения, регистрируете их и продолжаете работать? –

+0

вокруг кода, который бесконечно петляет, есть попытка/catch (...), который я регистрирую; журнал показывает иногда исключение (я не записывал детали) из кода, который петли, но программа продолжается; когда ошибка на самом деле происходит, не возникает никакого исключения, блок catch больше не достигнут –

ответ

0

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

1

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

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

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

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

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

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

+0

Я использую Winsock. Кроме того, клиент уже использует userdump.exe, но он вручную запускает дамп при зависании приложения (он никогда не сбой, просто зависает). Также используйте gflags для переключения полной кучи страниц. У меня также есть тестовый сценарий, работающий 24 часа в сутки 7 дней в неделю на локальном ПК, но без воспроизведения. –

+0

зависает = 'высокий CPU', или 'низкий CPU'? Высокий CPU будет соответствовать бесконечному циклу, скажем, в коррумпированной структуре данных. В этом случае демпинг процесса для получения последовательности столов должен быть поучительным. Низкий ЦП будет согласуется с потерей управления в управляемом событиями кодеке после неправильного пути ошибки, например. сокет. В этом случае дамп процесса endstate плюс больше диагек для изоляции поведения, приводящего к сбою, лучше всего делать imo. –

+0

У меня нет этой информации (низкий процессор/высокий процессор на зависании). Я добавлю его, если/когда я его получу. Но так как клиент может легко сбрасывать процесс, может быть, процессор не на 100%? –

0

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

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

+1

Отладочная сборка не зависит от клиента по моим знаниям (я должен был бы извлечь из нее некоторые функции, чтобы позволить им запускать ее на производственном сервере). Я добавил отладочную информацию в сборку релизов, но все же я пропущу утверждения и рекомендации кучи, которые вы рекомендуете. У меня есть тестовый файл, но я не могу воспроизвести его с помощью автоматического тестирования. Живая отладка не может быть и речи, скорость воспроизведения слишком низкая. C-style casts/type punning используются в некоторых местах, поэтому я попытаюсь это увидеть. –

1

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

full page heap проверка. Если у вашего приложения есть переполнение или переполнение кучи, он будет немедленно пойман.

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

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

+0

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

+0

@ adrian8400, тогда я бы очистил и смоделировал как можно больше. Двойная проверка всех возможных возвратов из системных вызовов, таких как сокеты и т. Д. –

Смежные вопросы