Стратегии поиска гейзенбагов
В настоящее время я снова нахожусь в ситуации, когда мне нужно найти причину ошибки, которая почти никогда не возникает, когда работает отладчик (возможно, какое-то состояние гонки). Единственное, что я могу придумать, чтобы найти это:
- Добавьте отладочные распечатки и утверждения в код, который говорит мне, что происходит без отладчика.
- Пошаговый код и продумайте каждую строку и возможные побочные эффекты, которые он может иметь.
В целом это очень расстраивает. Каковы ваши стратегии и опыт работы с такими ошибками?
Редактировать: я использую Visual C++ 2005, но я думаю, что вопрос касается многих (всех) языков и сред разработки.
3 ответа
Если вы можете определить точки, в которых проблема впервые видна (очевидно, не тогда, когда она вызвана), создайте там исключение и используйте Process Dumper, чтобы получить дамп для отладки после смерти.
Запустите ваши двоичные файлы Release за пределами IDE и затем присоедините отладчик. Это позволяет избежать специальной кучи и других флагов, которые запускаются внутри отладчика.
Если у вас есть ЛЮБОЕ представление о том, в чем заключается ошибка, извлеките этот код в минимально достаточное тестовое приложение, которое максимально забивает его - вы пытаетесь проверить его на предмет разрушения. Опять же, присоединяйте отладчик только после того, как код запущен и работает, чтобы избежать многих специфических для Debugger побочных эффектов.
Варианты осмотра - Сборка с /W4
просто чтобы убедиться, что ничего очевидного не пропущено. Проверьте код и предупреждения для приведений в стиле C или reinterpret_cast на случай, если кто-то отбросил чудесное, но важное предупреждение или сообщение об ошибке.
Я обнаружил, что запуск кода поверх моего кода C/C++/Java и проверка того, что я исправляю каждое предупреждение, которое он предлагает, приводят к тому, что эти условия гонки просто исчезают. Но это не решение. Никогда не используйте случайно. Вы должны понимать, что вы исправили и почему это решило проблему.
Я полагаю, что именно K (&& ||) R заявил, что обширные сообщения регистрации делали больше, чтобы помочь им отладить код, чем любой отладчик - особенно в многопоточных средах, но цитирование необходимо.
Тщательный просмотр очень подробной информации обо всех действиях, которые привели к возникновению ошибки, действительно очень помогает.
Когда все методы закончены и BoundsCheckers или RationalPurify не помогают. Я обычно использую очень тупую технику. Мы обнаружили это на первом курсе университета. По русски это называется очень грубо.
Итак, я начинаю с выбора подозрительного блока / модуля, который не работает в многопоточной среде. Если это невозможно, то структура программы пересматривается.
Когда модуль выбран, я комментирую небольшие блоки кода, пока исключение не исчезнет. Это позволяет определить причину (например, состояние гонки). Если на этом этапе вы можете сказать, что не так - тогда это здорово.
Если нет, то же метод применяется для обнаружения предусловия ошибки, поэтому я комментирую код, который предшествует блоку преступника.