Исправление ошибок сегментации в C++

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

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

6 ответов


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

  2. использовать gdb чтобы открыть консоль gdb.

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

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

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

  6. тип bt на gdb консоль, чтобы получить трассировку стека Ошибка Сегментирования.


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


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

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

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

  • GDB могу сказать вам, где сбой программы и позволит вам увидеть в каком контексте.
  • отчет поможет вам обнаружить много памяти ошибки.
  • С GCC вы также можете использовать брызговик С GCC и Clang вы можете использовать Дезинфицирующее Средство Для Адреса / Памяти. Он может обнаружить некоторые ошибки, которые Valgrind не делает, и потеря производительности легче.

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


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


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

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

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

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

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

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

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


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

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

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