Каковы лучшие практики для поиска ошибки в программе на C, которая появляется только в оптимизированной сборке - PullRequest
5 голосов
/ 23 июня 2011

Моя программа использует библиотеку третьей части, которая в какой-то момент выдает ошибку сегментации. Я попытался скомпилировать библиотеку с отладочными символами и без оптимизации компилятора, и сбой исчез. Я подозреваю, что оптимизация компилятора выявила эту ошибку. Каковы лучшие практики для отладки подобных случаев?

РЕДАКТИРОВАТЬ - (исправлено приведенное выше утверждение: «выявлено» вместо «вызвано»)

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

Ответы [ 7 ]

8 голосов
/ 23 июня 2011

То, что вы описываете, довольно распространено. И это почти никогда не бывает ошибкой в ​​оптимизации компилятора. Оптимизация многое делает для вашего кода. Переменные переупорядочиваются / оптимизируются и т. Д. Если у вас есть одно переполнение буфера, оно может просто переполнить память, что не составляет большого труда в сборке отладки, но эта память очень важна в сборке оптимизации.

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

8 голосов
/ 23 июня 2011

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

  • Индекс OutOfBounds
  • Возвращение адреса временного
  • Миллион других вещей
4 голосов
/ 23 июня 2011

Скомпилируйте с отладочными символами и оптимизацией компилятора, он также "надеюсь" не удастся.Разрешить системе генерировать основной файл (ulimit -c unlimited, затем перезапустить программу).Загрузите файл ядра в gdb, чтобы увидеть, что произошло.

Другим мощным инструментом является valgrind, запустите вашу программу в valgrind с параметром --db-attatch=yes, она остановит и запустит отладчик, как только обнаружит недопустимое чтение или запись.Недопустимые операции чтения / записи могут спровоцировать Segfault, и даже если они этого не делают, их все равно следует удалить.

Удачи,

2 голосов
/ 23 июня 2011

Если обратная трассировка ведет к сторонней библиотеке, используйте gdb для прерывания перед вызовом библиотеки.Убедитесь, что параметры, передаваемые в библиотеку, действительны (т. Е. Не являются неинициализированными указателями, не являются указателями на свободную память, не находятся вне диапазона и т. Д.)использовать strace для отслеживания вызовов функций, а затем попытаться определить путь выполнения в сторонней библиотеке?Используйте printf или другой системный вызов перед неудачным вызовом библиотеки, чтобы у вас была отправная точка в выводе strace.

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

2 голосов
/ 23 июня 2011

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

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

Оба эти метода полезны для общей отладки, и половина вашей работы уже выполнена, если вы можете надежно воспроизвести сбой.

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

0 голосов
/ 24 июня 2011

Если он срабатывает только при включении оптимизации, то это сильный намек, что вы где-то вызывали неопределенное поведение.К сожалению, этот UB может быть совсем рядом с кодом, который фактически генерировал segfault (как я обнаружил несколько раз в прошлом).

Каждый раз, когда это происходило со мной (что случалось не так часто), причиной было переполнение буфера где-то еще в коде.Тем не менее, я никогда не разрабатывал повторяемый, общеприменимый метод для поиска проблемы (если только вы не хотите вызывать часы, проходя через отладчик и ругаясь на общеприменимый метод).

0 голосов
/ 23 июня 2011

Что ж, анализ скомпилированного двоичного файла не поможет.

Так что прохождение кода позволяет выяснить, какая часть вызывает ошибку segfault. Я бы просто обработал ваш код вручную и начал комментировать. Как только вы найдете причину ошибки, вы сможете определить, что с ней делать. Возможно, стоит добавить printf s в выбранных местах, чтобы точно определить, где происходит сбой программы.

Думайте об этом как о бинарном поиске ошибки;)

...