C++: Где запустить, когда мои сбои приложения наугад помещают?

Я разрабатываю игру и когда я делаю определенное действие в игре, это отказывает. Таким образом, я пошел, отладив, и я видел свое приложение, разрушенное в простых операторах C++ как if, return... Каждый раз, когда я повторно выполняюсь, это отказывает случайным образом в одной из 3 строк, и это никогда не успешно выполняется.

строка 1:

if (dynamic) { ... } // dynamic is a bool member of my class

строка 2:

return m_Fixture; // a line of the Box2D physical engine. m_Fixture is a pointer.

строка 3:

return m_Density; // The body of a simple getter for an integer.

Я не получаю ошибок из приложения, ни ОС...

Есть ли подсказки, подсказки или приемы для отладки более эффективный и известны, что продолжается?

Вот почему я люблю Java...

Спасибо

6
задан Martijn Courteaux 7 July 2010 в 19:39
поделиться

15 ответов

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

10
ответ дан 8 December 2019 в 02:52
поделиться

Refactoring.

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

Таким образом вы наверняка обнаружите проблему (проблемы) и устраните множество других проблем.

-1
ответ дан 8 December 2019 в 02:52
поделиться

использовать GNU Debugger

0
ответ дан 8 December 2019 в 02:52
поделиться

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

В ЦЕЛЯХ ОБНАРУЖЕНИЯ попробуйте закомментировать некоторые подозрительные 'deletes'. Затем, если он больше не падает, вот и все.

0
ответ дан 8 December 2019 в 02:52
поделиться

несколько советов:
- запустите приложение в отладчике вместе с файлами символов (PDB).
- Как установить Visual Studio в качестве посмертного отладчика по умолчанию?
- установить отладчик по умолчанию для WinDbg Своевременная отладка
- проверить выделение памяти Переопределение нового и удаления и Переопределение malloc и free

1
ответ дан 8 December 2019 в 02:52
поделиться

Проверить указатели. Предположительно, вы разыменовываете нулевой указатель.

0
ответ дан 8 December 2019 в 02:52
поделиться

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

1
ответ дан 8 December 2019 в 02:52
поделиться

Посмотрите разборку. Практически любой отладчик C / C ++ будет рад показать вам машинный код и регистры, в которых произошел сбой программы. Регистры включают указатель инструкции (EIP или RIP на x86 / x64), где находится программа при остановке. Другие регистры обычно имеют адреса памяти или данные. Если адрес памяти 0 или неправильный указатель, в этом ваша проблема.

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

В Linux / BSD / Mac использование скриптовых функций GDB может здесь очень помочь. Вы можете создать сценарий так, чтобы после 20-кратного срабатывания точки останова это включало аппаратное наблюдение за адресом элемента массива 17. И т.д.

Вы также можете записать отладку в свою программу. Используйте функцию assert ().Где угодно!

Используйте assert для проверки аргументов каждой функции. Используйте assert для проверки состояния каждого объекта перед выходом из функции. В игре подтвердите, что игрок находится на карте, что у игрока есть здоровье от 0 до 100, подтвердите все, что вы можете придумать. Для сложных объектов напишите функции verify () или validate () в сам объект, который проверяет все о нем, а затем вызывает их из assert ().

Другой способ записи в отладке - это заставить программу использовать signal () в Linux или asm int 3 в Windows для взлома отладчика из программы. Затем вы можете записать в программу временный код, чтобы проверить, находится ли он на итерации 1117321 основного цикла. Это может быть полезно, если ошибка всегда возникает на 1117322. Таким образом программа будет выполняться намного быстрее, чем при использовании точки останова отладчика.

1
ответ дан 8 December 2019 в 02:52
поделиться

У меня раньше были подобные проблемы. Я пытался обновить графический интерфейс из разных потоков.

1
ответ дан 8 December 2019 в 02:52
поделиться

Простых операторов C ++ не существует. Условие «если» настолько просто, насколько просто оцениваемое вами условие. Возврат так же прост, как возвращаемое вами выражение.

Вы должны использовать отладчик и / или опубликовать код, который приводит к сбою. Не может быть много пользы, если в качестве информации указано «мое приложение разбилось».

2
ответ дан 8 December 2019 в 02:52
поделиться

Сбои / сбои сегментов обычно происходят, когда вы обращаетесь к участку памяти, к которому он не имеет доступа, или когда вы пытаетесь получить доступ к области памяти недопустимым способом (например, пытаетесь для записи в место только для чтения).

Есть много инструментов для анализа памяти, например, я использую Valgrind, который действительно отлично показывает, в чем проблема (не только номер строки, но и то, что вызывает сбой).

3
ответ дан 8 December 2019 в 02:52
поделиться

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

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

Помимо этих двух вещей, вы можете попробовать использовать отладчик, например Visual Studio или Eclipse и т.д..

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

.
4
ответ дан 8 December 2019 в 02:52
поделиться

Есть ли подсказки, советы или приемы, чтобы отлаживать более эффективно и узнать, что происходит?

  1. Запустите игру в отладчике, в точке падения проверьте значения всех аргументов. Либо с помощью окна наблюдения visual studio, либо с помощью gdb. С помощью "стека вызовов" проверьте родительские процедуры, попробуйте подумать, что могло пойти не так.
  2. В подозрительных (потенциально связанных с падением) подпрограммах, рассмотрите возможность дампа всех аргументов на stderr (если вы используете libsdl или на *nix-подобных системах), или напишите лог-файл, или отправьте дубликаты всех сообщений об ошибках, используя (в Windows) OutputDebugString. Это сделает их видимыми в окне "output" в visual studio или отладчике. Вы также можете писать "следы" (log("function %s was called", __FUNCTION__))
  3. Если вы не можете отлаживать сразу, создавайте дампы ядра при падении. В windows это можно сделать с помощью MiniDumpWriteDump, в linux это устанавливается где-то в конфигурационных переменных. дампы ядра могут обрабатываться отладчиком. Я не уверен, что VS express может работать с ними в Windows, но вы все равно можете отлаживать их с помощью WinDBG.
  4. если крах происходит внутри класса, проверьте *this аргумент. Он может быть недействительным или нулевым.
  5. Если ошибка действительно злая (неуловимое повреждение стека в многопоточном приложении, которое приводит к отложенному краху), напишите собственный менеджер памяти, который будет переопределять new/delete, обеспечивать альтернативу malloc (если ваше приложение по какой-то причине использует его, что возможно), И который блокирует всю неиспользуемую память с помощью VirtualProtect (windows) или альтернативы, специфичной для ОС. В этом случае все потенциально опасные операции будут мгновенно аварийно завершаться, что позволит вам отладить проблему (если у вас есть отладчик Just-In-Time) и мгновенно найти опасную рутину. Я предпочитаю такой "пользовательский менеджер памяти" boundschecker и тому подобным - по моему опыту он более полезен. В качестве альтернативы вы можете попробовать использовать valgrind, который доступен только в linux. Обратите внимание, что если ваше приложение очень часто выделяет память, вам понадобится большой объем оперативной памяти, чтобы иметь возможность блокировать каждый неиспользуемый блок памяти (потому что для блокировки блок должен быть размером PAGE_SIZE байт).
  6. В областях, где вам нужна проверка на вменяемость, используйте ASSERT, или (IMO лучшее решение) напишите процедуру, которая приведет к краху приложения (выбросив std::exception со значимым сообщением), если какое-то условие не будет выполнено.
  7. Если вы определили проблемную процедуру, пройдитесь по ней, используя step into/step over отладчика. Следите за аргументами.
  8. Если вы определили проблемную процедуру, но по каким-то причинам не можете отлаживать ее напрямую, после каждого оператора в этой процедуре выведите все переменные в stderr или лог-файл (fprintf или iostreams - на ваш выбор). Затем проанализируйте результаты и подумайте, как это могло произойти. Обязательно промывайте лог-файл после каждой записи, иначе вы можете пропустить данные непосредственно перед падением.

В целом, вы должны быть счастливы, что приложение где-то падает. Авария означает ошибку, которую можно быстро найти с помощью отладчика и уничтожить. Баги, не приводящие к краху программы, гораздо сложнее (пример действительно сложного бага: при 100000 значений входных данных, после нескольких сотен манипуляций со значениями, среди тысяч выходных, приложение выдает 1 абсолютно неверный результат, которого вообще не должно было быть)

Вот почему я люблю Java...

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

4
ответ дан 8 December 2019 в 02:52
поделиться

Если в операторах if происходит разыменование указателей, вы почти наверняка повреждаете стек (это объясняет, почему невинный return 0 приводит к краху...)

Это может произойти, например, при выходе за границы массива (вы должны использовать std::vector! ), при попытке strcpy строки, основанной на char[]-строке, в которой отсутствует окончание '\0' (следует использовать std::string!), при передаче неверного размера в memcpy (следует использовать конструкторы копирования!) и т.д.

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

1
ответ дан 8 December 2019 в 02:52
поделиться

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

Повреждение стека чаще всего происходит из-за «ошибки смещения на единицу».
Повреждение кучи происходит из-за того, что команда new / delete не обрабатывается должным образом, как, например, двойное удаление.

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

5
ответ дан 8 December 2019 в 02:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: