Подтвердить что ты не робот

Фиксация ошибок сегментации в С++

Я пишу кросс-платформенную программу на С++ для Windows и Unix. На стороне окна код будет компилироваться и не запускаться без проблем. На стороне Unix он будет компилироваться, однако, когда я пытаюсь запустить его, я получаю ошибку сегментации. Моя первоначальная догадка заключается в том, что проблема с указателями.

Каковы хорошие методологии для поиска и устранения ошибок ошибки сегментации?

4b9b3361

Ответ 1

  • Скомпилируйте ваше приложение с помощью -g, тогда вы будете иметь отладочные символы в двоичном файле.

  • Используйте gdb, чтобы открыть консоль gdb.

  • Используйте file и передайте его двоичный файл приложения в консоли.

  • Используйте run и передайте любые аргументы, которые необходимо запустить вашему приложению.

  • Сделайте что-нибудь, чтобы вызвать ошибку сегментации.

  • Введите bt в консоли gdb, чтобы получить трассировку стека с ошибкой сегментации.

Ответ 2

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

Ответ 3

Прежде чем возникнет проблема, постарайтесь избежать ее как можно больше:

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

Используйте соответствующие инструменты для отладки. В Unix:

  • GDB может сказать вам, где вы потерпели крах, и покажет, в каком контексте.
  • Valgrind поможет вам обнаружить много ошибок, связанных с памятью.
  • С GCC вы также можете использовать mudflap. С GCC и Clang вы можете использовать Address/Memory Sanitizer. Он может обнаружить некоторые ошибки, которых нет у Valgrind, и потеря производительности меньше.

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

Ответ 4

В Unix вы можете использовать valgrind для поиска проблем. Это бесплатно и мощно. Если вы предпочтете сделать это самостоятельно, вы можете перегрузить новые и удалить операторы, чтобы настроить конфигурацию, в которой у вас есть 1 байт с 0xDEADBEEF до и после каждого нового объекта. Затем проследите, что происходит на каждой итерации. Это может не уловить все (вам не гарантировано даже коснуться этих байтов), но он работал у меня в прошлом на платформе Windows.

Ответ 5

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

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

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

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

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

Используйте строки С++ и классы контейнеров, когда это возможно, вместо строк и массивов C-стиля. Рассмотрите возможность использования .at(i), а не [i], потому что это заставит проверку границ. Посмотрите, можно ли установить ваш компилятор или библиотеку для проверки границ на [i], по крайней мере, в режиме отладки. Ошибки сегментации могут быть вызваны переполнениями буфера, которые пишут мусор над совершенно хорошими указателями.

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

Ответ 6

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

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

Кроме того, вам просто нужно бросить в него свои лучшие психические энергии.