Как отладить трудно воспроизводимый сбой без полезного стека вызовов? - PullRequest
15 голосов
/ 18 января 2011

Я столкнулся со странным сбоем в нашем программном обеспечении, и у меня много проблем с его отладкой, и поэтому я ищу совет SO, как его решить.

Авария - это нарушение прав доступа при чтении указателя NULL:

Исключение первого шанса при $ 00CF0041.Класс исключения $ C0000005 с сообщением «нарушение прав доступа по адресу 0x00cf0041: чтение адреса 0x00000000».

Это происходит только «иногда» - мне пока не удалось выяснить какие-либо рифмы или причиныкогда - и только в основной теме.Когда это происходит, стек вызовов содержит одну неправильную запись:

Call stack with one line, Classes::TList::Get, address 0x00cf0041

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

На данный момент все остальные потоки неактивны (в основном это WaitForSingleObject или аналогичная функция). Я видел только этот сбой в основном потоке.Он всегда имеет один и тот же стек вызовов одной записи, в одном и том же методе по одному и тому же адресу.Этот метод может или не может быть связан - мы используем VCL в нашем приложении.Моя ставка, тем не менее, заключается в том, что что-то (возможно, довольно давно) повреждает стек, а адрес, где он падает, фактически случайный.Обратите внимание, что это был один и тот же адрес в нескольких сборках, хотя, вероятно, он не совсем случайный.

Вот что я пробовал:

  • Попытка надежно воспроизвести его на определенном уровне.точка.Я не нашел ничего, что воспроизводит это каждый раз, и пару вещей, которые иногда делают, или нет, без видимой причины.Это не достаточно узкие действия, чтобы сузить его до определенного раздела кода.Это может быть связано со временем, но в тот момент, когда интегрируется IDE, другие потоки обычно ничего не делают.Я не могу исключить проблему с многопоточностью, но думаю, что это маловероятно.
  • Сборка с дополнительными операторами отладки (дополнительная информация об отладке, дополнительные утверждения и т. Д.) После этого сбоя никогда не происходит.
  • Здание с Codeguard включена.После этого сбой никогда не происходит, и Codeguard не показывает ошибок.

Мои вопросы:

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

2.Какой у вас общий совет, как отследить причину этого сбоя?

Я использую Embarcadero RAD Studio 2010 (проект в основном содержит код C ++ Builder и небольшие объемыDelphi.)

Редактировать: Я подумал, что должен добавить, что на самом деле вызвало это.Был поток, который вызывал ReadDirectoryChangesW, а затем, используя GetOverlappedResult, ждал события, чтобы продолжить и что-то сделать с изменениями.Событие также было сигнализировано для завершения потока после установки флага состояния.Проблема была в том, что при выходе из потока он никогда не вызывал CancelIO.В результате Windows все еще отслеживала изменения и, вероятно, все еще записывала в буфер при изменении каталога, даже если буфер, перекрывающаяся структура и событие больше не существовали (равно как и контекст потока, в котором они были созданы). Когда CancelIOбыл вызван, больше не было сбоев.

Ответы [ 4 ]

15 голосов
/ 18 января 2011

Даже если трассировка стека, предоставленная IDE, не очень полная, это не значит, что в стеке по-прежнему нет полезной информации. Откройте представление CPU и проверьте панель стека; для каждого кода операции CALL адрес возврата помещается в стек. Так как стек растет вниз, вы найдете эти адреса возврата выше текущего местоположения стека, т.е. прокручивая вверх в области стека.

Стек для основного потока будет где-то около $ 00120000 или $ 00180000 (рандомизация адресного пространства в Vista и выше сделала его более случайным). Код для основного исполняемого файла будет где-то около $ 00400000. Вы можете спекулятивно исследовать элементы стека, которые не похожи на целочисленные данные (низкие значения) или адреса стека (диапазон $ 00120000 +), щелкнув правой кнопкой мыши на элементе стека и выбрав Follow -> Near Code , что заставит окно разборки перейти к этому адресу кода. Если это выглядит как недопустимый код, это, вероятно, неверная запись в трассировке стека. Если это допустимый код, это может быть код ОС (часто около 77000000 долларов и выше), в этом случае у вас не будет значащих символов, но время от времени вы будете сталкиваться с действительной верной записью стека.

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

4 голосов
/ 18 января 2011

Вот почему я сделал просмотрщик стека процессов :-) http://code.google.com/p/asmprofiler/wiki/ProcessStackViewer

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

Несколько раз мне помогло то, что я столкнулся с той же проблемой, что и ваша (нормальный обход стека Delphi невозможен из-заневерное состояние стека)

Редактировать: загружена новая версия, на сайте была старая версия (я сам много пользуюсь новой версией) http://asmprofiler.googlecode.com/files/AsmProfiler_Sampling%20v1.0.7.13.zip

2 голосов
/ 18 января 2011

Я не уверен на 100%, но из изображения, которое вы предоставили, я полагаю, что где-то в процессе выполнения вы пытаетесь получить доступ к объекту в TList, который имеет значение NULL.то есть:

AList[Index].SomeProperty/SomeMethod/etc. <-- error if (AList[Index] == NULL)

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

  • переходите шаг за шагом от выполнения основной формы (если нет исключений, пока там нет)

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

  • , если вышеупомянутое не может найти проблему,проверьте, не работают ли некоторые библиотеки

  • использовать журнал Eureka, иногда он тоже выходит из строя (очень мало раз), но обычно указывает в правильном направлении

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

2 голосов
/ 18 января 2011

Threading может быть причиной здесь. Обычно подозрительными являются потоки, которые используют структуры OVERLAPPED в стеке, и потоки, которые отправляют указатели на объекты в стеке другим потокам.

Может быть возможно восстановить частичную информацию о стеке, если вы используете Средства отладки для Windows и команду "dps".

...