Общие причины ошибок в версии выпуска, отсутствующей в режиме отладки


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

17 58

17 ответов:

много раз в режиме отладки в C++ все переменные инициализируются null, тогда как то же самое не происходит в режиме выпуска, если явно не указано.

проверьте наличие любых макросов отладки и неинициализированных переменных

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

также проверьте все исключения, например, не связанные напрямую с режимом выпуска, но иногда мы просто игнорируем некоторые критические исключения, такие как mem нарушение прав доступа в VC++, но то же самое может быть проблемой, по крайней мере, в других ОС, таких как Linux, Solaris. В идеале ваша программа не должна ловить такие критические исключения, как доступ к нулевому указателю.

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

другие различия могут быть:

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

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

  • переменные-члены и функции-члены в #ifdef _DEBUG, Так что класс имеет другой размер в отладочной сборке. Иногда #ifndef NDEBUG используется в сборке выпуска
  • аналогично, там другой #ifdef который бывает только в одном из двух билдов
  • отладочная версия использует отладочные версии системных библиотек, особенно функции выделения кучи и памяти
  • встроенные функции в сборке выпуска
  • порядок включения заголовочных файлов. Это не должно вызывать проблем, но если у вас есть что-то вроде #pragma pack это не было сброшено, то это может привести к неприятным проблемам. Подобные проблемы также могут возникнуть при использовании предварительно скомпилированные заголовки и принудительно включает
  • кэши: у вас может быть код, такой как кэши, который используется только в сборках выпуска, или ограничения размера кэша, которые отличаются
  • конфигурации проекта: конфигурации отладки и выпуска могут иметь разные настройки сборки (это, вероятно, произойдет при использовании IDE)
  • условия гонки, проблемы с синхронизацией и различные побочные эффекты, возникающие в результате отладки только кода

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

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

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

Он может, особенно если вы находитесь в области.

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

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

EDIT: я вижу, что другие упоминали об этом: конечно, у вас могут быть целые разделы кода, которые условно исключены, если не компилируются в режиме отладки. Если это так, я надеюсь, что это действительно отладке кода, а не что-то жизненно важное для корректности самой программы!

функции библиотеки CRT ведут себя по-разному в debug vs release (/MD vs /MDd).

strcpy_s,StringCchCopy и т. д. Даже если строки заканчиваются раньше, ваш szDest лучше n байт!

конечно, например, если вы используете конструкции типа

#if DEBUG

//some code

#endif

в .NET, даже если вы не используете условную компиляцию, как #if DEBUG, компилятор по-прежнему намного более либеральен с оптимизациями в режиме выпуска, чем в режиме отладки, что также может привести к выпуску только ошибок.

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

без более подробной информации я предположу, что "не ОК" означает, что он либо не компилируется, либо выдает какую-то ошибку во время выполнения. Проверьте, есть ли у вас код, который зависит от версии компиляции, либо через #if DEBUG операторы или с помощью методов, отмеченных

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

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

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

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

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

попробуйте скомпилировать код с включенной меньшей оптимизацией.

в непустой функции все пути выполнения должны заканчиваться оператором return.

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

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

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

Я только что испытал это, когда я вызывал функцию сборки, которая не восстановила предыдущие значения регистров.

в конфигурации" Release " VS компилировался с /O2, который оптимизирует код для скорости. Таким образом, некоторые локальные переменные, где просто сопоставление с регистрами ЦП (для оптимизации), которые были совместно использованы с вышеупомянутой функцией, приводят к серьезному повреждению памяти.

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

Я помню, когда мы строили dll и pdb в c/C++.

Я помню это:

  • добавление данных журнала когда-нибудь заставит ошибку двигаться или исчезнуть или сделать совершенно другую ошибку (так что это был не совсем вариант).
  • многие из этих ошибок, где из-за выделения char в strcpy и strcat и массивы char[] и т.д...
  • мы пропололи некоторые из них, запустив bounds checker и просто зафиксировав проблемы с выделением/освобождением памяти.
  • много раз мы систематически просматривали код и исправляли выделение символов (например, через все файлы).
  • определенно это что-то связанное с распределением памяти и управлением и ограничениями и различиями между режимом отладки и режимом выпуска.

а потом надеялся на лучшее.

Я иногда временно доставлял отладочные версии DLL клиентам, чтобы не задерживать производство, работая над ними жуки.