2009-07-31 9 views
2

У нас есть собственное приложение на C++, запущенное через COM + на сервере Windows 2003. Недавно я заметил из средства просмотра событий, что его исключения исключения, в частности исключение C0000005, которое, согласно http://blogs.msdn.com/calvin_hsia/archive/2004/06/30/170344.aspx, означает, что процесс пытается записать в память не в пределах своего адресного пространства, например, нарушения прав доступа.Как читать стек вызовов?

Запись в окне просмотра событий предоставляет стек вызовов:

LibFmwk UTIL_GetDateFromLogByDayDirectory (символ сопз *, класс utilCDate &) + 0xa26c LibFmwk UTIL_GetDateFromLogByDayDirectory (символ сопз *, класс utilCDate &) + 0x8af4 ! LibFmwk! UTIL_GetDateFromLogByDayDirectory (символ сопз *, класс utilCDate &) + 0x13a1 LibFmwk! utilCLogController :: GetFLFInfoLevel (аннулируются) Const + 0x1070 LibFmwk! utilCLogController :: GetFLFInfoLevel (аннулируются) Const + 0x186

Теперь я понимаю, что он дает мне имена методов, чтобы посмотреть, но у меня возникает ощущение, что адрес в конце каждой строки (например, + 0xa26c) пытается указать мне конкретную строку или инструкцию в этом методе.

Так что мои вопросы:

  1. Кто-нибудь знает, как я мог бы использовать этот адрес или любую другую информацию в стеке вызовов, чтобы определить, какую строку в коде его падение над на?
  2. Есть ли там какие-либо ресурсы, которые я мог бы читать, чтобы лучше понимать стеки вызовов,
  3. Есть ли какие-либо инструменты для бесплатного использования/раскрытия, которые могли бы помочь в анализе стека вызовов, возможно, путем присоединения к файлу символов отладки и/или двоичным файлам ?

Edit: В соответствии с просьбой, вот метод, который, как представляется, вызывает проблему:

BOOL UTIL_GetDateFromLogByDayDirectory(LPCSTR pszDir, utilCDate& oDate) 
{ 
BOOL bRet = FALSE; 

if ((pszDir[0] == '%') && 
    ::isdigit(pszDir[1]) && ::isdigit(pszDir[2]) && 
    ::isdigit(pszDir[3]) && ::isdigit(pszDir[4]) && 
    ::isdigit(pszDir[5]) && ::isdigit(pszDir[6]) && 
    ::isdigit(pszDir[7]) && ::isdigit(pszDir[8]) && 
    !pszDir[9]) 
{ 
    char acCopy[9]; 
    ::memcpy(acCopy, pszDir + 1, 8); 
    acCopy[8] = '\0'; 

    int iDay = ::atoi(&acCopy[6]); 
    acCopy[6] = '\0'; 
    int iMonth = ::atoi(&acCopy[4]); 
    acCopy[4] = '\0'; 
    int iYear = ::atoi(&acCopy[0]); 

    oDate.Set(iDay, iMonth, iYear); 

    bRet = TRUE; 
} 

return (bRet); 

}

Это код, написанный 10 лет назад членом нашей компании который уже давно ушел, поэтому я не могу точно знать, что это делает, но я знаю, что он участвует в процессе переименования каталога журнала с «Сегодня» на конкретную дату, например % 20090329. Индексирование массива, memcpy и адрес операторов делают его довольно подозрительным.

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

Большое спасибо! Энди

+1

Если вы создаете с помощью отладочных символов, вы можете получить фактический номер строки, а не смещение байта. –

+0

Спасибо, что указали это. –

+0

Итак, вы уверены, что переданный pszDir имеет длину не менее 10 символов? Это, безусловно, сбой, если это не так. – jussij

ответ

3

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

Но, находясь в вашей ситуации, я бы скорее исследовал эту проблему под отладчиком (например, отладчик MSVS или windbg); как альтернатива (если авария происходит на сайте клиента), вы можете создать дамп аварийной ситуации и изучить ее локально - это можно сделать с помощью Windows MiniDumpWriteDump API или утилиты SysInternals ProcDump (http://download.sysinternals.com/Files/procdump.zip).

Убедитесь, что все необходимые файлы символов созданы и доступны (также установите путь к серверу символов Microsoft, чтобы также можно было разрешить точки доступа к DLL-файлам).

ИМХО это только то, что вам нужно: http://www.dumpanalysis.org - это лучший ресурс для освещения всех ваших вопросов. Рассмотрите также обзор этого PDF - http://windbg.info/download/doc/pdf/WinDbg_A_to_Z_color.pdf

+0

Это золото! Очень интересные ссылки! – Karel

1

Пункт 2 и 3 легко ответил:

3-й точки. Любой отладчик. Для этого они созданы. Установите ваш отладчик для разрыва этого специального исключения. Вы должны быть в состоянии щелкнуть себя через столбец и найти разные вызовы в стеке (по крайней мере, delphi может это сделать, поэтому визуальная студия также должна быть в состоянии). Компиляция без оптимизации, если это возможно. OllyDBG также может работать - возможно, в сочетании с его функциями отслеживания.

2-й пункт.Любая информация о x86 Assembler, Reverseengineering ... Попытка: OpenRCE, NASM Documentation, ASM Community.

1-й пункт. Столбец говорит вам о функциях. Я не знаю, написана ли она в порядке или в противоположном порядке - так может быть, что первая строка является последней вызываемой функцией или первой вызываемой функцией. Следуйте вызовам с помощью отладчика. Иногда вы можете изменить между asm и кодом (в зависимости от отладчика, файлов карт ...). Если у вас нет источника - изучите ассемблер, прочитайте об обратном проектировании. Прочтите документацию о функциях, которые вы вызываете в сторонних компонентах. Возможно, вы не удовлетворите предварительное условие.

Если вы можете сказать немного больше о программе (какие части исходного кода у вас есть, это библиотека, вызов вовлечен ?, ...)


Теперь некоторый код чтение:

Функция принимает указатель на строку с нулевым завершением и ссылку на объект даты. Указатель считается действительным!

Функция проверяет, что строка находится в определенном формате (%, за которым следует 8 цифр, за которой следует \ 0). Если это не так, оно возвращает false. Эта проверка (большая, если) обращается к указателю без каких-либо проверок валидности. Длина не проверяется, и если указатель указывает где-то в диком виде, это пространство доступно. Я не знаю, вызовет ли более короткая строка. Это не должно быть связано с тем, как оценивается & &.

Затем в стеке выделяется некоторая память. Числовая часть строки копируется в нее (это нормально), и буфер получает свое завершение \ 0. Атоис извлекает числа. Это будет работать из-за разных используемых начальных местоположений и \ 0-завершения после каждой части. Как-то сложно, но приятно. Некоторые комментарии сделали бы все ясно.

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

В любом случае - кроме отсутствующей проверки указателя на строку, эта функция является звуковой, а не причиной вашей проблемы. Исключение составляет только место. Найдите аргументы, которые передаются в эту функцию. Всегда ли они действительны? Сделайте некоторые записи.

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

+0

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

+0

np - Я здесь, чтобы помочь, а не для очков. –

5

Другие говорили об этом между линиями, но не явно. посмотреть на:

LibFmwk!UTIL_GetDateFromLogByDayDirectory(char const *,class utilCDate &) + 0xa26c 

0xa26c смещение огромный, путь мимо конца функции. у отладчика, очевидно, нет соответствующих символов для LibFmwk, поэтому он полагается на экспорт DLL и показывает смещение относительно ближайшего, которое он может найти.

Итак, да, получите правильные символы, а затем это будет легкий ветерок. UTIL_GetDateFromLogByDayDirectory здесь не виноват.

Смежные вопросы