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

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

Ответ 1

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

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

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

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

Ответ 2

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

Ответ 3

Другие отличия могут быть:

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

Ответ 4

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

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

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

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

Ответ 5

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

Ответ 6

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

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

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

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

Ответ 7

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

#if DEBUG

//some code

#endif

Ответ 8

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

Ответ 9

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

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

Ответ 10

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

Ответ 11

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

Ответ 12

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

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

Ответ 13

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

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

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

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

Ответ 14

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

Ответ 15

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

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

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

Ответ 16

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

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

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

Ответ 17

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

Я помню это:

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

И затем надеялся на лучшее.

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