У меня здесь проблема типа «Кот Шредингера» - моя программа (на самом деле набор тестов для моей программы, но, тем не менее, программа) дает сбой, но только при сборке в режиме выпуска и только при запуске из командной строки . Посредством отладки пещерного человека (т.е. повсюду неприятных сообщений printf ()) я определил метод тестирования, при котором происходит сбой кода, хотя, к сожалению, фактический сбой, похоже, происходит в каком-то деструкторе, поскольку последние сообщения трассировки, которые я вижу, находятся в другие деструкторы, которые выполняются чисто.
Когда я пытаюсь запустить эту программу внутри Visual Studio, она не дает сбоев. То же самое происходит при запуске из WinDbg.exe. Сбой происходит только при запуске из командной строки. Это происходит под Windows Vista, кстати, и, к сожалению, у меня сейчас нет доступа к машине XP для тестирования.
Было бы очень хорошо, если бы я мог заставить Windows распечатать трассировку стека или что-то еще, кроме простого завершения программы, как если бы она вышла без ошибок. Есть ли у кого-нибудь совет относительно того, как я могу получить здесь более значимую информацию и, надеюсь, исправить эту ошибку?
Изменить: проблема действительно была вызвана массивом вне границ, о котором я подробнее расскажу в этом сообщении . Спасибо всем за помощь в поиске этой проблемы!
Ответы:
В 100% случаев, которые я видел или слышал, когда программа на C или C ++ нормально работает в отладчике, но не работает при запуске извне, причина заключалась в записи за концом локального массива функции. (Отладчик помещает больше в стек, поэтому вероятность перезаписи чего-то важного снижается.)
источник
Когда я раньше сталкивался с подобными проблемами, это обычно происходило из-за инициализации переменной. В режиме отладки переменные и указатели автоматически инициализируются нулем, а в режиме выпуска - нет. Поэтому, если у вас есть такой код
int* p; .... if (p == 0) { // do stuff }
В режиме отладки код в if не выполняется, но в режиме выпуска p содержит неопределенное значение, которое вряд ли будет 0, поэтому код выполняется, часто вызывая сбой.
Я бы проверил ваш код на наличие неинициализированных переменных. Это также может относиться к содержимому массивов.
источник
До сих пор ни один ответ не попытался дать серьезный обзор доступных методов отладки релизных приложений:
Сборки Release и Debug ведут себя по-разному по многим причинам. Вот отличный обзор. Каждое из этих различий может вызвать ошибку в сборке Release, которой нет в сборке Debug.
Наличие отладчика также может изменить поведение программы как для выпускных, так и для отладочных сборок. Смотрите этот ответ. Короче говоря, по крайней мере, отладчик Visual Studio автоматически использует Debug Heap при подключении к программе. Вы можете отключить кучу отладки, используя переменную среды _NO_DEBUG_HEAP. Вы можете указать это либо в свойствах вашего компьютера, либо в настройках проекта в Visual Studio. Это может сделать сбой воспроизводимым с подключенным отладчиком.
Подробнее об отладке повреждения кучи здесь.
Если предыдущее решение не работает, вам нужно перехватить необработанное исключение и подключить посмертный отладчик в случае сбоя. Вы можете использовать, например, WinDbg для этого, подробности о доступных посмертных отладчиках и их установке на MSDN
Вы можете улучшить свой код обработки исключений, и если это производственное приложение, вам следует:
а. Установите собственный обработчик завершения, используя
std::set_terminate
Если вы хотите отладить эту проблему локально, вы можете запустить бесконечный цикл внутри обработчика завершения и вывести текст на консоль, чтобы уведомить вас, что
std::terminate
вызове. Затем подключите отладчик и проверьте стек вызовов. Или вы распечатываете трассировку стека, как описано в этом ответе.В производственном приложении вы можете захотеть отправить домой отчет об ошибке, в идеале вместе с небольшим дампом памяти, который позволит вам проанализировать проблему, как описано здесь.
б. Используйте структурированный механизм обработки исключений Microsoft, который позволяет перехватывать как аппаратные, так и программные исключения. См. MSDN . Вы можете защитить части своего кода с помощью SEH и использовать тот же подход, что и в а), для отладки проблемы. SEH предоставляет дополнительную информацию о возникшем исключении, которое вы можете использовать при отправке отчета об ошибке из производственного приложения.
источник
На что следует обратить внимание:
Переполнение массива - отладчик Visual Studio вставляет заполнение, которое может остановить сбои.
Условия гонки - если у вас задействовано несколько потоков, многие из них появляются только тогда, когда приложение выполняется напрямую.
Связывание - ваша сборка выпуска использует правильные библиотеки.
Что стоит попробовать:
Minidump - очень простой в использовании (просто посмотрите его в msdn) даст вам полный аварийный дамп для каждого потока. Вы просто загружаете результат в визуальную студию, и это как если бы вы отлаживали во время сбоя.
источник
Вы можете установить WinDbg в качестве посмертного отладчика. Это запустит отладчик и подключит его к процессу, когда произойдет сбой. Чтобы установить WinDbg для посмертной отладки, используйте параметр / I (обратите внимание, что он пишется с большой буквы ):
Подробнее здесь .
Что касается причины, это, скорее всего, унифицированная переменная, как предполагают другие ответы.
источник
После многих часов отладки я наконец нашел причину проблемы, которая действительно была вызвана переполнением буфера, вызвавшим однобайтовую разницу:
char *end = static_cast<char*>(attr->data) + attr->dataSize;
Это ошибка заборного столба (ошибка с разницей в одну), которая была исправлена:
char *end = static_cast<char*>(attr->data) + attr->dataSize - 1;
Странно было то, что я несколько раз обращался к _CrtCheckMemory () в разных частях кода, и они всегда возвращали 1. Я смог найти источник проблемы, поместив «return false;» вызывает в тестовом случае, а затем в конечном итоге методом проб и ошибок определяет, где была ошибка.
Спасибо всем за комментарии - сегодня я много узнал о windbg.exe! :)
источник
Несмотря на то, что вы создали свой exe-файл как выпуск, вы все равно можете создавать файлы PDB (база данных программ), которые позволят вам выполнять трассировку стека и выполнять ограниченное количество проверок переменных. В настройках вашей сборки есть возможность создавать файлы PDB. Включите это и повторно установите связь. Затем попробуйте сначала запустить из IDE, чтобы увидеть, не произойдет ли сбой. Если так, то отлично - вы готовы смотреть на вещи. Если нет, то при запуске из командной строки вы можете сделать одно из двух:
Когда вас попросят указать на файлы PDB, просмотрите их, чтобы найти. Если PDB были помещены в ту же папку вывода, что и ваши EXE или DLL, они, вероятно, будут загружены автоматически.
PDB предоставляет ссылку на источник с достаточной символьной информацией, чтобы можно было видеть трассировки стека, переменные и т. Д. Вы можете проверять значения как обычно, но имейте в виду, что вы можете получить ложные показания, поскольку проход оптимизации может иметь только значение появляются в регистрах или события происходят в другом порядке, чем вы ожидаете.
NB: здесь я подразумеваю среду Windows / Visual Studio.
источник
Подобные сбои почти всегда возникают из-за того, что среда IDE обычно устанавливает для содержимого неинициализированной переменной нули, ноль или какое-либо другое такое «разумное» значение, тогда как при исходном запуске вы получите любой случайный мусор, который система подбирает.
Таким образом, ваша ошибка почти наверняка заключается в том, что вы используете что-то вроде указателя до того, как он был должным образом инициализирован, и вам сходит с рук в среде IDE, потому что он не указывает на что-либо опасное - или значение обрабатывается вашим проверка ошибок - но в режиме выпуска делает что-то неприятное.
источник
Чтобы иметь аварийный дамп, который можно проанализировать:
Вы также должны проверить инструменты в инструментах отладки для Windows . Вы можете отслеживать приложение и видеть все исключения первого шанса, которые были до исключения второго шанса.
Надеюсь, это поможет...
источник
Отличный способ отладить такую ошибку - включить оптимизацию для вашей отладочной сборки.
источник
Однажды у меня возникла проблема, когда приложение вело себя так же, как ваше. Это оказалось неприятным переполнением буфера в sprintf. Естественно, это сработало при запуске с подключенным отладчиком. Что я сделал, так это установил фильтр необработанных исключений ( SetUnhandledExceptionFilter ), в котором я просто блокировал бесконечно (используя WaitForSingleObject на поддельном дескрипторе со значением тайм-аута INFINITE).
Итак, вы могли бы что-то вроде:
Затем я подключил отладчик после того, как ошибка проявилась (программа gui перестала отвечать).
Тогда можно либо взять дамп и поработать с ним позже:
Или сразу отладить. Самый простой способ - отследить, где контекст процессора был сохранен механизмом обработки исключений во время выполнения:
Команда будет искать адресное пространство стека для записи (ов) КОНТЕКСТА при условии длины поиска. Я обычно использую что-то вроде l? 10000 . Обратите внимание: не используйте необычно большие числа в качестве записи, которую вы обычно ищете, рядом с фреймом фильтра необработанных исключений. 1003f - это комбинация флагов (я считаю, что она соответствует CONTEXT_FULL), используемая для захвата состояния процессора. Ваш поиск будет выглядеть примерно так:
Как только вы получите результаты, используйте адрес в команде cxr:
Это приведет вас к этому новому КОНТЕКСТУ точно во время сбоя (вы получите именно трассировку стека во время сбоя приложения). Дополнительно используйте:
чтобы узнать, какое именно исключение произошло.
Надеюсь, это поможет.
источник
Иногда это происходит из-за того, что вы заключили важную операцию в макрос assert. Как вы, возможно, знаете, «assert» оценивает выражения только в режиме отладки.
источник
Что касается ваших проблем с получением диагностической информации, пробовали ли вы использовать adplus.vbs в качестве альтернативы WinDbg.exe? Чтобы присоединиться к запущенному процессу, используйте
Или запустить приложение в случае, если сбой произойдет быстро:
Полную информацию о adplus.vbs можно найти по адресу: http://support.microsoft.com/kb/286350
источник
Ntdll.dll с прикрепленным отладчиком
Одно небольшое различие между запуском программы из IDE или WinDbg и запуском из командной строки / рабочего стола заключается в том, что при запуске с подключенным отладчиком (например, IDE или WinDbg) ntdll.dll использует другую реализацию кучи, которая выполняет небольшую проверку о выделении / освобождении памяти.
Вы можете прочитать некоторую важную информацию в неожиданной пользовательской точке останова в ntdll.dll . Одним из инструментов, который может помочь вам определить проблему, является PageHeap.exe .
Анализ сбоев
Вы не писали, какой у вас "сбой". Как только программа выйдет из строя и предложит вам отправить информацию об ошибке в Microsoft, вы сможете щелкнуть по технической информации и проверить хотя бы код исключения, а с некоторыми усилиями вы даже сможете выполнить посмертный анализ (см. Heisenbug : Программа WinApi вылетает на некоторых компьютерах) для инструкций)
источник
Vista SP1 имеет действительно хороший генератор аварийных дампов, встроенный в систему. К сожалению, по умолчанию он не включен!
См. Эту статью: http://msdn.microsoft.com/en-us/library/bb787181(VS.85).aspx
Преимущество этого подхода заключается в том, что в уязвимой системе не требуется устанавливать дополнительное программное обеспечение. Возьми его и разорви, детка!
источник
По моему опыту, это большинство проблем с повреждением памяти.
Например :
char a[8]; memset(&a[0], 0, 16); : /*use array a doing some thing */
очень возможно быть нормальным в режиме отладки при запуске кода.
Но в выпуске это могло бы привести к сбою.
Для меня слишком утомительно рыться там, где память не ограничена.
Использование некоторых инструментов, таких как Visual Leak Detector (windows) или valgrind (linux), является более разумным выбором.
источник
Я видел много правильных ответов. Однако ничто не помогло мне. В моем случае было неправильное использование инструкций SSE с невыровненной памятью . Взгляните на свою математическую библиотеку (если вы ее используете) и попробуйте отключить поддержку SIMD, перекомпилировать и воспроизвести сбой.
Пример:
Проект включает mathfu и использует классы с вектором STL: std :: vector <mathfu :: vec2> . Такое использование, вероятно, вызовет сбой во время создания элемента mathfu :: vec2, поскольку распределитель по умолчанию STL не гарантирует требуемого 16-байтового выравнивания. В этом случае, чтобы доказать идею, можно определить
#define MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT 1
перед каждым включением mathfu , перекомпилировать в конфигурации Release и снова проверить.В Debug и RelWithDebInfo конфигурация работала хорошо для моего проекта, но не в релизе один. Причина такого поведения, вероятно, заключается в том, что отладчик обрабатывает запросы на выделение / освобождение и выполняет некоторую учетную запись памяти для проверки и проверки доступа к памяти.
Я испытал ситуацию в средах Visual Studio 2015 и 2017.
источник
Что-то подобное случилось со мной однажды с GCC. Оказалось, что это слишком агрессивная оптимизация, которая включалась только при создании финальной версии, а не в процессе разработки.
Ну, по правде говоря, это была моя вина, а не gcc, поскольку я не заметил, что мой код полагался на тот факт, что эта конкретная оптимизация не была бы проведена.
Мне потребовалось много времени, чтобы отследить это, и я пришел к нему только потому, что спросил в группе новостей, и кто-то заставил меня подумать об этом. Итак, позвольте мне ответить вам одолжением на случай, если это произойдет и с вами.
источник
Я нашел эту статью полезной для вашего сценария. ISTR параметры компилятора были немного устаревшими. Изучите параметры проекта Visual Studio, чтобы узнать, как создавать файлы pdb для сборки выпуска и т. Д.
источник
Подозрительно, что это произошло бы вне отладчика, а не внутри; запуск в отладчике обычно не меняет поведения приложения. Я бы проверил различия среды между консолью и IDE. Кроме того, очевидно, скомпилируйте выпуск без оптимизаций и с отладочной информацией и посмотрите, повлияет ли это на поведение. Наконец, ознакомьтесь с инструментами посмертной отладки, которые предложили здесь другие люди, обычно вы можете получить от них какую-то подсказку.
источник
Отладка сборок выпуска может быть сложной задачей из-за оптимизаций, изменяющих порядок, в котором строки вашего кода кажутся выполняемыми. Это действительно может сбить с толку!
Один из способов, по крайней мере, сузить проблему - использовать MessageBox () для отображения быстрых операторов, указывающих, в какой части программы находится ваш код («Запуск Foo ()», «Запуск Foo2 ()»); начните размещать их в верхней части функций в той области вашего кода, которую вы подозреваете (что вы делали в то время, когда он разбился?). Когда вы можете сказать, какая функция, измените окна сообщений на блоки кода или даже отдельные строки внутри этой функции, пока вы не сузите ее до нескольких строк. Затем вы можете начать распечатывать значения переменных, чтобы увидеть, в каком состоянии они находятся в момент сбоя.
источник
Попробуйте использовать _CrtCheckMemory (), чтобы узнать, в каком состоянии находится выделенная память. Если все идет хорошо, _CrtCheckMemory возвращает TRUE , иначе FALSE .
источник
Вы можете запускать свое программное обеспечение с включенными глобальными флагами (см. Инструменты отладки для Windows). Очень часто это помогает решить проблему.
источник
Сделайте так, чтобы ваша программа генерировала мини-дамп при возникновении исключения, затем откройте его в отладчике (например, в WinDbg). Ключевые функции, на которые стоит обратить внимание: MiniDumpWriteDump, SetUnhandledExceptionFilter
источник
Вот случай, который кто-то может найти поучительным. Он разбился только в выпуске Qt Creator - не при отладке. Я использовал файлы .ini (поскольку я предпочитаю приложения, которые можно копировать на другие диски, а не те, которые теряют свои настройки в случае повреждения реестра). Это относится к любым приложениям, которые хранят свои настройки в дереве каталогов приложений. Если сборки отладки и выпуска находятся в разных каталогах, у вас также могут быть разные настройки. У меня были отмечены предпочтения в одном, но не в другом. Это оказалось причиной моего крушения. Хорошо, что нашел.
Ненавижу это говорить, но я диагностировал сбой только в MS Visual Studio Community Edition; после установки VS, позволив моему приложению вылететь в Qt Creator, и выбрав его в отладчике Visual Studio . Хотя в моем приложении Qt не было информации о символах, оказалось, что в библиотеках Qt она была. Это привело меня к обидной линии; так как я мог видеть, какой метод вызывается. (Тем не менее, я думаю, что Qt - это удобный, мощный и кроссплатформенный фреймворк LGPL.)
источник
У меня тоже была эта пробема. В моем случае режим RELEASE содержал msvscrtd.dll в определении компоновщика. Мы удалили его, и проблема решена.
В качестве альтернативы, добавление / NODEFAULTLIB к аргументам командной строки компоновщика также решило проблему.
источник
У меня была эта ошибка, и vs вылетел даже при попытке! Clean! мой проект. Поэтому я вручную удалил файлы obj из каталога Release, и после этого все было нормально.
источник
Я согласен с Рольфом. Поскольку воспроизводимость очень важна, у вас не должно быть режима без отладки. Все ваши сборки должны быть отлаживаемыми. Наличие двух целей для отладки более чем вдвое увеличивает отладочную нагрузку. Просто отправьте версию для «режима отладки», если она не пригодна для использования. В таком случае сделайте его пригодным для использования.
источник