Форум: "Прочее";
Текущий архив: 2013.11.03;
Скачать: [xml.tar.bz2];
ВнизПадение приложения, crash без визуализации Найти похожие ветки
← →
Es (2013-05-14 18:22) [0]Есть приложение, работает на сервере (в смысле, что на Win server 2008), но не в виде сервиса, а как обычное GUI приложение + много потоков в виде обработчиков.
Беда в том, что иногда приложение просто исчезает. Смотрят - а его нету в процессах, никаких сообщений, ну как будто не было.
Приложение под еврикой, но никаких .elf отчетов рядом не обнаруживается.
Возникает вопрос - как копать и куда. В каких случаях windows вообще может терминировать процесс, причем так втихую? Как искать место затыка?
Если это исключение в главном потоке, то почему оно не перехватывается стандартным кодом VCL?
← →
Плохиш © (2013-05-14 18:34) [1]Смотри логи виндовс.
← →
Дмитрий С © (2013-05-14 18:34) [2]А в журнале про это что-нибудь написалось?
← →
Es (2013-05-14 18:35) [3]как именно
← →
Rouse_ © (2013-05-14 18:39) [4]
> В каких случаях windows вообще может терминировать процесс,
> причем так втихую? Как искать место затыка?
90 процентов что портится стек, а раз стека нет - значит нет никаких SEH фреймов и исключений, включая глобальный обработчик, собстенно о этом говорит и несрабатывание EurekaLog, который работает на перехвате вызова raise.
Если ручками со стеком ничего не делаешь - значит кривая работа с памятью.
← →
Es (2013-05-14 18:44) [5]нашел один из крешей в eventvwr:
Faulting application OfflineServer.exe, version 1.0.1.103, time stamp 0x2a425e19, faulting module ntdll.dll, version 6.0.6002.18541, time stamp 0x4ec3e3d5, exception code 0xc0000005, fault offset 0x00041440, process id 0x2ae0, application start time 0x01ce4ed2616a69ba.
← →
Es (2013-05-14 18:48) [6]Rouse_, а делать то что, как можно искать проблему? Приложение достаточно большое, чтобы каждую строчку просматривать, да и утопический это подход.
Как я понимаю, ставить try..except по коду и пытаться писать исключения в лог - это тоже не прокатит.
А куда копать тогда...
← →
Плохиш © (2013-05-14 18:50) [7]
> 0xc0000005
Access Violation
← →
clickmaker © (2013-05-14 18:51) [8]> exception code 0xc0000005
Access denied
Смотри, куда твоя тулза просит доступ, и где ей может быть отказано.
← →
Rouse_ © (2013-05-14 18:52) [9]c0000005 - AccessViolation
твой оффсет: 0х41440 + база загрузки
Запускай приложение и становись бряком на этот адрес - там уже и смотри.
← →
Rouse_ © (2013-05-14 18:54) [10]А, кстати у тебя внятрях NTDLL падает, так что может вместо базы придется инстанс этой библиотеки добавлять.
← →
Rouse_ © (2013-05-14 19:02) [11]зы: забыл, в случае ntdll адрес рассчитываешь $41440 + GetModuleHandle(ntdll32), переходишь в CPU View, ставиш бряк, запускаешь процесс, ждеш сработки - по стеку вызовов уточняешь что за функция расположена по данному адресу (в случае если в отладчике не размапятся имена, обычно они видны).
Потом переопределяешь ее на свой вызов (любым доступным способом) и логируешь вызовы, пока не упрешся в падение.
Если я прав и падает из-за порчи стека, то полагаться на try..finally смысла не имеет - они не сработают. В этом случае используй механизм VEH
http://msdn.microsoft.com/en-us/library/windows/desktop/ms681420(v=vs.85).aspx
← →
Es (2013-05-14 19:15) [12]Rouse_, нихрена не понял арифметики.
Вообще, если падает внутрях ntdll - по идее, причем тут мой модуль? Получается, код ntdll сделал нечто такое, что некорректно сработало с памятью, верно?
>fault offset 0x00041440
он пишется относительно чего? Если относительно "нуля" - то я так понимаю, просто по этому адресу и располагается Ntdll?
← →
Es (2013-05-14 19:16) [13]Rouse_, а, кажется понял. Винда пишет адрес:
>fault offset 0x00041440
относительно начала модуля, который она указывает:
>faulting module ntdll.dll
?
← →
Rouse_ © (2013-05-14 19:18) [14]угу
← →
Es (2013-05-14 19:23) [15]все равно непонятно - а почему это исключение в ntdll не перехватывается программой?
Какой-то настолько глобальный трындец, что портится стек, а при этом в некую неизвестную функцию ntdll передаются параметры (ну собственно из-за стека), которые заставляют ntdll обратиться в непонятную область памяти?
← →
Es (2013-05-14 19:27) [16]большая беда в том, что падения бывают раз в неделю при круглосуточной работе. А бывают и 3 раза в день...
И дело в том, что на девелоп-машине я не могу запустить программу с рабочими данными. А если я не запущу с рабочими данными - есть подозрение, что до вызова нужной функции вообще дело не дойдет.
Плюс программа крутится на windows server 2008, а у меня Win 7 рабочая.
Могу вытащить ntdll с той машины, но как по смещению понять функцию? ...
← →
Rouse_ © (2013-05-14 19:37) [17]
> а почему это исключение в ntdll не перехватывается программой?
Потомучто в случае разрушения стека механизм отлавливания исключений перестает работаеть, ибо SEH фреймы работают то-же через стек.
Функция в NTDLL может работать с памятью, ну например какой-нить VirtualFree которому ты передал адрес страницы со стека или еще чего.
> Могу вытащить ntdll с той машины, но как по смещению понять
> функцию? ...
В любом отладчике открыть и посотреть что там расположено.
← →
Es (2013-05-14 21:51) [18]воспользовался статьей: http://www.twintechs.com/2008/11/how-to-find-what-function-is-at-a-dll-offset-without-having-debug-symbols/
Запустил OllyDbg на искомой машине, подгрузил туда ntdll.dll
Он начинался с адреса: 76EE1000. В статье прочитал, что это значит базовый адрес: 76EE0000
Приплюсовал свое смещение 41440, получилось: 76F21440
Получилось такое:
http://img14.imageshost.ru/img/2013/05/14/image_51926b0405576.png
(инструкция MOV EDI, EDI - могло из-за этого?)
← →
Es (2013-05-14 21:51) [19]Пошел вверх до значка "$" - написано, что так отладчик обозначает функции, получился адрес: 76F21349
http://img14.imageshost.ru/img/2013/05/14/image_51927c3d40728.png
Далее сказано идти в " Debug > Call DLL Export"... И офигеть, там функции отсортированы не по адресам... Просмотрел весь список!!! Убил глаза в хлам... Функции с началом адреса 76F21349 не нашел...
← →
Es (2013-05-14 21:55) [20]на всякий случай выкладываю целевой ntdll.dll - http://webfile.ru/6519741 (526 кбайт, нужно выбрать "скачать напрямую"), может кто подсобит...
← →
clickmaker © (2013-05-14 22:04) [21]> MOV EDI, EDI - могло из-за этого?)
вряд ли. Это просто NOP по сути
← →
clickmaker © (2013-05-14 22:13) [22]может быть, дело в этом: http://habrahabr.ru/post/90377/
← →
Rouse_ © (2013-05-14 22:17) [23]Из-за этого не могло.
MOV EDI, EDI - это пролог MS API использующих технологию HOT_PATCH.
В данном случае я опознаю данную функцию как RaiseException.
В итоге ты просто получил адрес вызова финального исключения в отсутствие обработчика оного.
Получается теперь у тебя только один способ и остался - использование VEH.
Установи VEH обработчик и попробуй логировать исключения через него, с целью получить адрес вылета.
Есть нюанс - VEH работает перед SEH, поэтому ты будешь получать море исключений, пока не выйдешь на то, которое тебе нужно.
← →
Rouse_ © (2013-05-14 22:22) [24]
> clickmaker © (14.05.13 22:04) [21]
Тезка, не болтайте ерундой :)
Изменение регистров в случае MOV отличается от штатного поведения NOP.
Ну и раз уж пошла ссылка на хабр, то для Delphi сообщества более адекватной и менее ошибочной (даже в плане изложения материала) будет данная ссылка :)
http://habrahabr.ru/post/178393/
← →
clickmaker © (2013-05-14 22:46) [25]> Тезка, не болтайте ерундой :)
собственно, все ссылки в гугле по mov edi,edi и ведут на хот-патч
← →
Rouse_ © (2013-05-14 22:57) [26]
> clickmaker © (14.05.13 22:46) [25]
> > Тезка, не болтайте ерундой :)
>
> собственно, все ссылки в гугле по mov edi,edi и ведут на
> хот-патч
Сань, в приведенной тобой ссылке нет упоминания о хотпатче.
Более того есть куча ошибок, о части которых я уведомил автора статьи.
К примеру (даже не буду рассматривать пропуск стаба): "Кроме того, если размер функции меньше 5 байт, перехват просто невозможен."
Это есть неверно.
Ну либо:
"3. Скопировать туда первые 5 байт исходной функции до установки туда перехватчика."
С учетом что максимальный размер инструкции может быть равен 14-ти байтам, я не думаю что разрезание инструкции по ее середке будет оправдано :)
← →
clickmaker © (2013-05-14 23:13) [27]> [26] Rouse_ © (14.05.13 22:57)
да хрен с ней, со статьей. Я предположил просто, не может ли попытка этого хот-патча привести к исключению...
← →
Rouse_ © (2013-05-14 23:29) [28]
> clickmaker © (14.05.13 23:13) [27]
Если правильно его использовать - то нет, тем-более данная метода обычно выполняется сторонним приложением, а не тем, которое падает.
При неправильном использовании можем вылезти на вот такие вот нюансы: http://alexander-bagel.blogspot.ru/2012/11/debuger-2.html#false_disasm
В любом случае здесь явно не та ситуация.
Раз приложение падает раз через три, то имеем на руках проблемы с памятью.
Они могут быть разные - от банальной неинициализованной локальной переменной, до кривой работы с памятью (ну например у нас "некоторые" любят ошибаться в размерностью при работе с данными, забывая -1 при указании диапазона цикла, или добавляя лишнюю единицу при адресации нестрокового буффера)
← →
Es (2013-05-15 00:08) [29]
> MOV EDI, EDI - это пролог MS API использующих технологию
> HOT_PATCH.
> В данном случае я опознаю данную функцию как RaiseException.
>
> В итоге ты просто получил адрес вызова финального исключения
> в отсутствие обработчика оного.
ох долго мне переваривать эти строки...
Насколько я понял, HOT_PATCH - это такая штука, что в начало функции вставляется двухбайтовая команда mov EDI, EDI (которая ничего по сути не делает), чтобы потом было легче начало функции перезатереть и переправить на свою функцию (аля перехват)?
Уже тут я не понял. Если рассмотреть вывод винды:>fault offset 0x00041440
я так понимаю, относительно начало модуля ntdll.dll по указанному смещению находилась инструкция, выполнение которой и завершилось исключением? Обработка исключения при этом нифига не произошла, потому что к тому времени стек был нагло испохаблен.
Но по этому адресу, если я все сделал правильно, находится инструкция MOV EDI, EDI (безобидная). Означает ли это, что вместо данной инструкции на момент выполнения программы там находилась другая инструкция?
Может, тогда стоит запустить программу и просто считать какая реально команда находится в загруженном приложении по этому смещению?
Также я не понял фразу:
> В данном случае я опознаю данную функцию как RaiseException.
что имеется в виду под "данную функцию"? И каким образом произошло опознание, по представленной картинке?
← →
Es (2013-05-15 00:18) [30]
> Установи VEH обработчик и попробуй логировать исключения
> через него, с целью получить адрес вылета.
вот не понял опять :(
Я так попытался прочитать про VEH, как я понял это возможность перехватывать исключения. При этом я получу информацию о них, несмотря на то, что callstack разрушен. Но я не понял:
1) почему собственно обычные исключения перестают работать, если callstack испоганен? Исключения же не в стеке хранятся?
2) каким все таки образом поможет VEH? Вот получу я управление после исключения.. а дальше? (
← →
Cobalt © (2013-05-15 01:23) [31]может на серваке какая утилита криво перехватывает функции?
Сравни загруженные в АП длл-ки
← →
Es (2013-05-15 02:15) [32]да не, исключено почти. Корпоративный сервер, особо никакого лишнего софта (хакерского).
Очень нагруженная программа, крутится неделями, может неделю работать, может за день два раза упасть... Кривой код и проблема с памятью во сто крат вероятнее...
← →
Германн © (2013-05-15 02:51) [33]
> ох долго мне переваривать эти строки...
> > Установи VEH обработчик и попробуй логировать исключения
> > через него, с целью получить адрес вылета.
>
> вот не понял опять :(
>
Ох действительно долго. Ну разве что Розыч почему-то захочет помочь. :)
← →
Германн © (2013-05-15 03:27) [34]
> Ну разве что Розыч почему-то захочет помочь. :)
>
Как-то иначе я его совет: "Установи VEH обработчик" я просто не воспринимаю. :)
Понимаю, что Саша живёт в своём мире. :)
← →
Dimka Maslov © (2013-05-15 08:28) [35]В своё время я долго блися с подобной проблемой падения многопоточного сервера. Как я понял это происходит из-за плохой синхронизации потоков при обращении к менеджеру памяти. Причём, как на С++, так и на Delphi. Возможных решений два - написать свой менеджер памяти или сделать приложение службой, заставив систему перезапускать его в случае сбоя. Второе решение гораздо проще.
← →
Rouse_ © (2013-05-15 10:31) [36]
> что имеется в виду под "данную функцию"? И каким образом
> произошло опознание, по представленной картинке?
Немного промахнулся, это LdrInitializeThunk.text:77F11440 ; __stdcall LdrInitializeThunk(x, x)
.text:77F11440 public _LdrInitializeThunk@8
.text:77F11440 _LdrInitializeThunk@8 proc near
.text:77F11440
.text:77F11440 arg_0 = dword ptr 8
.text:77F11440 arg_4 = dword ptr 0Ch
.text:77F11440
.text:77F11440 mov edi, edi
.text:77F11442 push ebp
.text:77F11443 mov ebp, esp
.text:77F11445 push [ebp+arg_4]
.text:77F11448 push [ebp+arg_0]
.text:77F1144B call _LdrpInitialize@8 ; LdrpInitialize(x,x)
.text:77F11450 push 1
.text:77F11452 push [ebp+arg_0]
.text:77F11455 call _ZwContinue@8 ; ZwContinue(x,x)
.text:77F1145A push eax
.text:77F1145B call _RtlRaiseStatus@4 ; RtlRaiseStatus(x)
.text:77F11460 int 3 ; Trap to Debugger
.text:77F11461 nop
.text:77F11462 nop
.text:77F11463 nop
.text:77F11464 nop
.text:77F11465 nop
.text:77F11465 _LdrInitializeThunk@8 endp
Что впрочем тоже мало что нам дает.
> 1) почему собственно обычные исключения перестают работать,
> если callstack испоганен? Исключения же не в стеке хранятся?
>
Исключения нет, но в стеке размещаются SEH фреймы, которые и перехватывают исключения.
> 2) каким все таки образом поможет VEH? Вот получу я управление
> после исключения.. а дальше? (
Ты поймаешь точный адрес исключения и сможешь вытащить всю цепочку вызовов, чтобы определить какой именно код вызвал падение.
← →
Плохиш © (2013-05-15 10:36) [37]Вроде в Delphi тоже Remote Debugger есть.
← →
Es (2013-05-15 12:15) [38]
> Немного промахнулся, это LdrInitializeThunk
классно. А как ты узнал, что это LdrInitializeThunk?
У меня адрес исключения -76F21440
, на твоей системе в той же DLL я так понял это77F11440
, но откуда столько строк под этим адресом? Если был бы приведен листинг:.text:77F11440 mov edi, edi
.text:77F11442 push ebp
.text:77F11443 mov ebp, esp
.text:77F11445 push [ebp+arg_4]
.text:77F11448 push [ebp+arg_0]
.text:77F1144B call _LdrpInitialize@8 ; LdrpInitialize(x,x)
.text:77F11450 push 1
.text:77F11452 push [ebp+arg_0]
.text:77F11455 call _ZwContinue@8 ; ZwContinue(x,x)
.text:77F1145A push eax
...
...
то это прям совпадало бы с тем, что я видел. Но откуда эта надстройка:.text:77F11440 ; __stdcall LdrInitializeThunk(x, x)
.text:77F11440 public _LdrInitializeThunk@8
.text:77F11440 _LdrInitializeThunk@8 proc near
.text:77F11440
.text:77F11440 arg_0 = dword ptr 8
.text:77F11440 arg_4 = dword ptr 0Ch
.text:77F11440
Это говорит о том, что по адресу 77F11440 находится непосредственно точка входа в LdrInitializeThunk?
А как он может быть точкой исключения? Управление передано по этому адресу... и тут же исключение? Там же никакого кода, первая команда же MOV EDI, EDI - она же ничего не делает!
Не понимаю... Что за адрес исключения тогда в журнале винды? (
← →
Rouse_ © (2013-05-15 12:20) [39]
> классно. А как ты узнал, что это LdrInitializeThunk?
Ты открывал в OllyDebug, а у меня лицензионная IDA Pro + установленные символы, поэтому информации выдается в разы больше.
> Там же никакого кода, первая команда же MOV EDI, EDI - она
> же ничего не делает!
Ну вариантов на самом деле много, самый простой - по данному адресу были выставлены неверные аттрибуты страницы, что и привело к падению.
Либо второй вариант, из-за срыва стека получить точный адрес ошибки не удалось и вылез вот этот вот оффсет.
← →
Es (2013-05-15 12:22) [40]
> Ты поймаешь точный адрес исключения и сможешь вытащить всю
> цепочку вызовов, чтобы определить какой именно код вызвал
> падение.
а что значит точный адрес исключения? Почему адрес исключения винды не точный? Она ведь по идее должна отловить именно указатель на ту инструкцию, которая вызвала исключение?
> и сможешь вытащить всю цепочку вызовов, чтобы определить
> какой именно код вызвал падение.
а как я вытащу цепочку вызовов, если callstack"у хана на тот момент уже? (
Страницы: 1 2 3 вся ветка
Форум: "Прочее";
Текущий архив: 2013.11.03;
Скачать: [xml.tar.bz2];
Память: 0.57 MB
Время: 0.004 c