Виправлення помилок сегментації в C ++


95

Я пишу крос-платформну програму C ++ для Windows та Unix. На стороні вікна код буде скомпільований і не виконає жодних проблем. На стороні Unix він буде скомпільований, однак, коли я намагаюся його запустити, я отримую помилку сегментації. Я спочатку здогадуюсь, що є проблема з покажчиками.

Які хороші методології можна знайти та виправити помилки помилок сегментації?

Відповіді:


134
  1. Складіть свою програму -g, тоді ви будете мати символи налагодження у двійковому файлі.

  2. Використовуйте gdbдля відкриття консолі gdb.

  3. Використовуйте fileта передайте в консоль двійковий файл вашого додатка.

  4. Використовуйте runта передавайте будь-які аргументи, необхідні для запуску вашої програми.

  5. Зробіть щось, щоб викликати помилку сегментації .

  6. Введіть btв gdbконсоль, щоб отримати трасування стека з помилкою сегментації .


Що означає мати компіляцію gв контексті CMake?
Schütze

2
Увімкніть тип побудови налагодження. Один із способів є cmake -DCMAKE_BUILD_TYPE=Debug.
Антонін Дечимо,

36

Іноді збій сам по собі не є справжньою причиною проблеми - можливо, пам'ять була розбита раніше, але пройшов певний час, щоб проявити себе корупція. Перевірте valgrind , який має безліч перевірок на проблеми з покажчиками (включаючи перевірку меж масиву). Це покаже вам, з чого починається проблема , а не лише лінія, де відбувається збій.


19

Перш ніж проблема виникне, намагайтеся якомога більше її уникати:

  • Компілюйте та запускайте свій код якомога частіше. Знайти несправну деталь буде простіше.
  • Спробуйте інкапсулювати низькорівневі / схильні до помилок підпрограми, так що вам рідко доводиться працювати безпосередньо з пам'яттю (зверніть увагу на моделювання вашої програми)
  • Підтримуйте набір тестів. Огляд того, що зараз працює, що вже не працює тощо, допоможе вам з’ясувати, де проблема ( Boost-тест - це можливе рішення, я не використовую його сам, але документація може допомогти зрозуміти, який вид інформація повинна відображатися).

Використовуйте відповідні інструменти для налагодження. На Unix:

  • GDB може сказати вам, де ви програмуєте програму, і дозволить побачити, в якому контексті.
  • Valgrind допоможе вам виявити багато помилок, пов'язаних з пам'яттю.
  • З GCC ви також можете використовувати mudflap З GCC, Clang, а з жовтня експериментально MSVC ви можете використовувати дезінфікуючий засіб Address / Memory . Він може виявити деякі помилки, яких Valgrind не робить, і втрата продуктивності стає меншою. Він використовується шляхом складання з -fsanitize=addressпрапором.

Нарешті я б порекомендував звичні речі. Чим більше ваша програма читабельною, ремонтопридатною, чіткою та акуратною, тим легшим буде її налагодження.


5

У Unix ви можете використовувати valgrindдля пошуку проблем. Це безкоштовно та потужно. Якщо ви вважаєте за краще зробити це самостійно, ви можете перевантажити оператори newand та deleteвстановити конфігурацію, де у вас є 1 байт 0xDEADBEEFдо і після кожного нового об'єкта. Потім відстежуйте, що відбувається на кожній ітерації. Це може не вловити все (ви навіть не можете гарантовано доторкнутися до цих байтів), але раніше це працювало для мене на платформі Windows.


1
ну це буде 4 байти, а не 1 ... але принцип чудовий.
Йонас Вагнер,

1
Чи можу я зробити посилання на мій налагоджувач купи ? :-)
fredoverflow

Дій. Ми всі прагнемо допомагати іншим тут, тому слід додати все, що може допомогти.
Wheaties

Хоча перевантаження newі deleteможе бути надзвичайно корисним, використання -fsanitize=addressє кращим варіантом, оскільки компілятор компілюється під час виявлення проблем і автоматично скидає пам'ять на екран, що полегшує налагодження.
Тарік Веллінг,

3

Так, проблема з покажчиками. Швидше за все, ви використовуєте той, який не ініціалізований належним чином, але також можливо, що ви заплутаєте управління пам’яттю подвійними безкоштовними або якимись подібними.

Щоб уникнути неініціалізованих покажчиків як локальних змінних, спробуйте оголосити їх якомога пізніше, бажано (а це не завжди можливо), коли вони можуть бути ініціалізовані значущим значенням. Переконайтеся, що вони матимуть значення перед тим, як їх використовувати, вивчивши код. Якщо у вас виникають труднощі з цим, ініціалізуйте їх константою нульового покажчика (зазвичай пишеться як NULLабо 0) та перевірте.

Щоб уникнути неініціалізованих покажчиків як значень-членів, переконайтесь, що вони правильно ініціалізовані в конструкторі та оброблені належним чином у конструкторах копіювання та операторах присвоєння. Не покладайтесь на initфункцію управління пам’яттю, хоча для іншої ініціалізації можна.

Якщо ваш клас не потребує конструкторів копіювання або операторів присвоєння, ви можете оголосити їх як приватні функції-члени і ніколи не визначати. Це призведе до помилки компілятора, якщо вони явно або неявно використовуються.

Використовуйте розумні вказівники, коли це можливо. Велика перевага тут полягає в тому, що якщо ви будете дотримуватися їх і використовувати їх послідовно, ви зможете повністю уникнути написання, deleteі ніщо не буде подвійно видалено.

Використовуйте рядки C ++ та класи контейнерів, коли це можливо, замість рядків та масивів у стилі C. Подумайте про використання, .at(i)а не про те [i], що це змусить перевірити межі. Перевірте, чи можна встановити ваш компілятор або бібліотеку для перевірки меж [i], принаймні в режимі налагодження. Помилки сегментації можуть бути спричинені перевитратами буфера, які записують сміття над цілком хорошими вказівниками.

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


1

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

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

Окрім цього, вам просто потрібно вкласти в це свої найкращі психічні енергії.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.