Хороший способ отладить повреждение значения стека

Каков хороший способ отладки повреждения значения стека. В моей программе иногда адрес указателя this меняется после возврата метода, который завершает работу файлового дескриптора. Я отлаживал программу часами, но не могу найти проблему.

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

Мне удалось обнаружить, когда возникает ошибка, я скомпилировал код в 64-битном режиме. Адрес этого изменен с 0xxxxxxx на 0x1000000xxxxxxx. Я проверяю адрес этого в методах, где возникает ошибка, которую я узнал при изменении адреса (см. Первый параграф для этого).

Есть ли другой способ выяснить причину этой проблемы?


person lauw    schedule 28.01.2014    source источник
comment
Добавить параметры компилятора -fstack-protector или -fstack-protector-all?   -  person Brett Hale    schedule 28.01.2014
comment
Часы автоматически удаляются, когда переменная выходит за пределы области действия. Запустите программу до заведомо хорошей точки. Найдите адрес переменной, которая становится поврежденной, и добавьте наблюдение за содержимым этого адреса вместо переменной, т.е. если адрес переменной равен 0x12345678 (а не содержимое, которое было бы 0xxxxxxxxx как на ваш вопрос), затем установите аппаратные часы записи на * (void **) 0x12345678 и продолжите свою программу.   -  person atomice    schedule 28.01.2014
comment
Указатель this в стеке изменяется. Программа продолжает выполняться, но когда я вызываю переменную класса, (эта + позиция переменной) будет недействительной. Проблема возникает только тогда, когда я быстро создаю и уничтожаю объект (этот объект содержит дескриптор файла и закрывает его при уничтожении). Есть ли способ добавить программу для часов автоматически? Это значительно упростило бы дело.   -  person lauw    schedule 28.01.2014


Ответы (1)


Вы можете попробовать address-sanitizer. Он доступен в gcc 4.8:

Добавлен AddressSanitizer, быстрый детектор ошибок памяти, который можно включить через -fsanitize=address. Инструкции по доступу к памяти будут приспособлены для обнаружения переполнения кучи, стека и глобального буфера, а также ошибок использования после освобождения. Чтобы получить более красивые трассировки стека, используйте -fno-omit-frame-pointer. AddressSanitizer доступен на IA-32/x86-64/x32/PowerPC/PowerPC64 GNU/Linux и на x86-64 Darwin.

В GCC (но явно не в clang) вам нужно указать -fsanitize=address в оба флагах компилятора и флагах компоновщика, как описано в этот связанный ответ.

person Ali    schedule 28.01.2014
comment
Этот инструмент обнаружил переполнение буфера стека, но трассировка стека не очень удобна (я использовал параметр -fno-omit-frame-pointer, трассировку стека можно найти здесь: pastebin.com/b81eUnZq). Инструмент выводит: project+0x47744c. Как я могу добраться до этого места в исходном коде? Я использую eclipse как IDE. - person lauw; 28.01.2014
comment
Пожалуйста, попробуйте скомпилировать с -ggdb3. Это обычно дает хорошие стеки вызовов. - person Ali; 28.01.2014
comment
Если подумать, вы можете полностью отключить оптимизацию (-O0), а также добавить -ggdb3 и -fno-omit-frame-pointer (я знаю, что вы добавили последнее). Надеюсь это поможет. - person Ali; 28.01.2014
comment
Проблема решена. Большое спасибо! Я трачу более 8 часов на отладку этой проблемы. - person lauw; 28.01.2014
comment
@ user35774 Я рад, что это помогло! Какой флаг помог? -ggdb3 или -O0? - person Ali; 28.01.2014
comment
Я не тестировал -ggd3 и не получил хорошей трассировки стека с -O0. Мне удалось решить проблему с дизассемблированием в Eclipse. Вы можете передать адрес в режиме дизассемблирования, когда находитесь в правильном исполняемом файле/библиотеке. Идите на один шаг вверх, а затем вниз, таким образом вся сборка будет загружена правильно (по какой-то причине я приземлился в середине звонка). Теперь вы можете видеть, откуда был сделан вызов. Вы также можете увидеть исходный код между кодом сборки. - person lauw; 28.01.2014
comment
@user35774 user35774 К сожалению, мой gcc довольно старый и в нем нет адреса-сантайзера, поэтому я не могу его проверить сам. В любом случае, я рад, что вам удалось решить проблему. - person Ali; 28.01.2014