Как отладить ошибки перезаписи стека с помощью Valgrind? - PullRequest
7 голосов
/ 28 апреля 2011

Я просто потратил некоторое время на поиски ошибки, которая сводилась к следующему. Код ошибочно перезаписывал стек, и я думаю, что он записал поверх адреса возврата вызова функции. После возврата программа зависнет и стек будет поврежден. Запуск программы в valgrind вернет ошибку, такую ​​как:

vex x86->IR: unhandled instruction bytes: 0xEA 0x3 0x0 0x0
==9222== valgrind: Unrecognised instruction at address 0x4e925a8.

Я полагаю, это потому, что возвращение переместилось в случайное место, содержащее вещи, которые не были действительными кодами операций x86. (Хотя я почему-то подозреваю, что этот адрес 0x4e925a8 оказался на исполняемой странице. Я полагаю, что valgrind выдаст другую ошибку, если это не так.)

Я уверен, что проблема была в типе перезаписи стека, и с тех пор я исправил его. Сейчас я пытаюсь подумать, как можно более эффективно отлавливать подобные ошибки. Очевидно, что valgrind не может предупредить меня, если я перезаписываю data в стеке, но, возможно, он может перехватить, когда кто-то переписывает адрес возврата в стеке. В принципе, он может обнаружить, когда происходит что-то вроде «push EIP» (поэтому он может указать, где находятся адреса возврата в стеке).

Мне было интересно, кто-нибудь знает, может ли это сделать Вальгринд или еще кто-нибудь? Если нет, можете ли вы прокомментировать другие предложения относительно ошибок отладки этого типа.

Ответы [ 2 ]

6 голосов
/ 02 мая 2011

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

Если вы работаете на одной из поддерживаемых платформ, сборка с -fmudflap и связь с -lmudflap даст вам намного лучшие результаты для ошибок такого рода.Дополнительные документы здесь .

Udpdate:

Многое изменилось за 6 лет с момента получения этого ответа.В Linux инструментом для поиска переполнения стека (и кучи) является AddressSanitizer , поддерживаемый последними версиями GCC и Clang.

5 голосов
/ 28 апреля 2011

Если проблема возникает достаточно детерминистически, чтобы вы могли указать на конкретную функцию, у которой разбит ее стек (в одном повторяемом тестовом примере), вы можете в gdb:

  1. Разбить при входе в эту функцию
  2. Найти, где хранится адрес возврата (это относительно %ebp (на x86) (который сохраняет значение %esp при входе в функцию), я не уверен, есть ли какое-либо смещение).
  3. Добавить точку наблюдения по этому адресу.Вы должны выполнить команду watch с вычисленным числом, а не с выражением, потому что с выражением gdb будет пытаться переоценить его после каждой инструкции вместо установки прерывания, и это будет очень медленно.
  4. Пусть функция завершится.

Я еще не работал с поддержкой python, доступной в gdb7, но это должно позволить автоматизировать это.

...