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


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

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

6 53

6 ответов:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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