Может ли неуправляемое исключение первого шанса вызвать сбой / перезапуск?
Последующие вопросы: "При расследовании аварии я должен исследовать только исключения второго шанса? В каких случаях мне также нужно исследовать дамп исключения первого шанса?"
Мои вопросы немного широки, но мне интересно, что на самом деле ответ. Я прочитал множество статей, в которых говорится, что исключения из первого шанса вряд ли вызовут сбой приложения; это исключение второго шанса, которое вызывает это. Простой поиск в Google не отвечает на мой вопрос напрямую.
РЕДАКТИРОВАТЬ: Вот примеры статей, но есть еще много других:
Что такое исключение для первого шанса?:
"Для кода без обработки исключений отладчик получит уведомление об исключении второго шанса и остановится с необработанным исключением".
Программа вылетает, но Debug Diag говорит, что это исключение из первого шанса, это правильно?
Конечно, по определению, только второе случайное исключение может привести к сбою кода, то есть то, которое НЕ было обработано кодом?
У меня периодически возникает проблема, когда мое приложение перезагружается или происходит сбой (нет ошибки в средстве просмотра событий), но перед перезапуском Adplus генерирует некоторые первые исключения AccessViolation. Никаких исключений второго шанса.
Ниже приведен фрагмент FULLDUMP_FirstChance_av_AccessViolation для WinDbg.exe:
PROBLEM_CLASSES:
HEAP_CORRUPTION
Tid [0x16e8]
Frame [0x02]: ntdll!RtlAllocateHeap
HEAP_CORRUPTION
Tid [0x16e8]
Frame [0x02]: ntdll!RtlAllocateHeap
INVALID_POINTER_READ
Tid [0x16e8]
Frame [0x00]: ntdll!ExpInterlockedPopEntrySListFault
NOSOS
Tid [0x16e8]
BUGCHECK_STR: HEAP_CORRUPTION_HEAP_CORRUPTION_INVALID_POINTER_READ_NOSOS
Образцы стеков вызовов ниже:
# ChildEBP RetAddr Args to Child
00 085aec28 7c91020e 00000007 00c407d8 00c40000 ntdll!ExpInterlockedPopEntrySListFault (FPO: [0,2,0])
01 085aec58 7c91019b 00c407d8 00000030 00000000 ntdll!RtlpAllocateFromHeapLookaside+0x1d (FPO: [Non-Fpo])
02 085aee84 78134d83 00c40000 00000000 00000030 ntdll!RtlAllocateHeap+0x1c2 (FPO: [Non-Fpo])
03 085aeea4 78160e30 00000030 0000002f 085aeecc msvcr80!malloc(unsigned int size = 0x30)+0x7a (FPO: [1,0,0]) (CONV: cdecl) [f:\dd\vctools\crt_bld\self_x86\crt\src\malloc.c @ 163]
04 085aeebc 7c4221b3 00000030 00000003 7c422f20 msvcr80!operator new(unsigned int size = 0x30)+0x1d (FPO: [Non-Fpo]) (CONV: cdecl) [f:\dd\vctools\crt_bld\self_x86\crt\src\new.cpp @ 59]
05 085aeed4 7c423315 00000030 00000000 ae218f51 msvcp80!std::_Allocate<char>(unsigned int _Count = 0x30, char * __formal = 0x00000000 "")+0x15 (FPO: [Non-Fpo]) (CONV: cdecl) [f:\dd\vctools\crt_bld\self_x86\crt\src\xmemory @ 44]
06 085aef0c 7c4233c4 0000002a 00000000 085af028 msvcp80!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Copy(unsigned int _Newsize = 0x2a, unsigned int _Oldlen = 0)+0x55 (FPO: [Non-Fpo]) (CONV: thiscall) [f:\dd\vctools\crt_bld\self_x86\crt\src\xstring @ 2020]
07 085aef20 7c423779 0000002a 00000000 085af200 msvcp80!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Grow(unsigned int _Newsize = 0x2a, bool _Trim = false)+0x22 (FPO: [2,0,0]) (CONV: thiscall) [f:\dd\vctools\crt_bld\self_x86\crt\src\xstring @ 2050]
08 085aef3c 7c425e55 0000002a 00000000 0000002a msvcp80!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::append(class std::basic_string<char,std::char_traits<char>,std::allocator<char> > * _Right = 0x0000002a, unsigned int _Roff = 0, unsigned int _Count = 0x2a)+0x58 (FPO: [Non-Fpo]) (CONV: thiscall) [f:\dd\vctools\crt_bld\self_x86\crt\src\xstring @ 969]
09 085aef4c 60baed1e 085af028 ae262fd2 085af1a4 msvcp80!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::append(class std::basic_string<char,std::char_traits<char>,std::allocator<char> > * _Right = 0x085af028 " S1 S1 Card number: ************8706
")+0xd (FPO: [1,0,0]) (CONV: thiscall) [f:\dd\vctools\crt_bld\self_x86\crt\src\xstring @ 956]
0a 085af1a4 7c802662 00000100 00000000 00000000 aipoptrv19!DllUnregisterServer+0x1f15e
0b 085af234 7c42317a 00000000 00000000 0000000f kernel32!WaitForSingleObject+0x12 (FPO: [Non-Fpo])
0c 085af274 60bc1fd8 60baa1cb 0865d680 0000001c msvcp80!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> >(void)+0x11 (FPO: [0,0,4]) (CONV: thiscall) [f:\dd\vctools\crt_bld\self_x86\crt\src\xstring @ 576]
0d 085af278 60baa1cb 0865d680 0000001c 00000002 aipoptrv19!DllUnregisterServer+0x32418
0e 085af2e4 60bb227c 00000001 085af420 0865d648 aipoptrv19!DllUnregisterServer+0x1a60b
0f 085af34c 7c425e45 085af404 00000000 ffffffff aipoptrv19!DllUnregisterServer+0x226bc
10 085af35c 60b97724 72506f44 69746e69 0000676e msvcp80!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::assign(class std::basic_string<char,std::char_traits<char>,std::allocator<char> > * _Right = 0x72506f44)+0xd (FPO: [1,0,0]) (CONV: thiscall) [f:\dd\vctools\crt_bld\self_x86\crt\src\xstring @ 1044]
11 085af45c 78261414 00000002 403110f4 7824f516 aipoptrv19!DllUnregisterServer+0x7b64
12 085af468 7824f516 fffffffe 781f2c2e 0000001c mfc80!_AfxDispatchCall(<function> * __formal = 0x40b59c84, void * __formal = 0x085af6b8, unsigned int __formal = 0x85a0003)+0x10 (CONV: stdcall) [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\olecall.cpp @ 40]
13 085af470 781f2c2e 0000001c 7824f49b 00000008 mfc80!CCmdTarget::CallMemberFunc(struct AFX_DISPMAP_ENTRY * pEntry = 0x6d756e20, unsigned short wFlags = 0x6562, struct tagVARIANT * pvarResult = 0x20202020 Empty, struct tagDISPPARAMS * pDispParams = 0x2a2a2a2a, unsigned int * puArgErr = 0x2a2a2a2a)+0x1ad (CONV: thiscall) [f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\oledisp1.cpp @ 1064]
Ошибка связана с повреждениями кучи и неверными указателями, о которых я все еще изучаю. Я новичок в кучах и malloc, и я только что научился отлаживать с помощью WinDbg. Я просто хотел знать, не трачу ли я свое время на изучение распределения памяти, когда это не является моим приоритетом и не решит ли я по-настоящему проблему. (Конечно, знать о кучах - это хорошо, но решение главной проблемы - главный приоритет)
Я уверен в своем конфигурационном файле adplus и уверен, что он создаст полный дамп для всех исключений второго шанса. Я попробовал это на примере приложения.
Приложение не падает, оно просто неожиданно и периодически перезагружается без ошибки просмотра событий. Его можно периодически создавать при использовании определенного сервиса.
Вот мои возможные мысли, если файлы дампа на самом деле не являются причиной проблемы:
- Другой процесс (не прикрепленный на моем adplus) вызвал перезапуск.
- Полные дампы исключений второго шанса просто не генерируются.
- Другие (есть мысли?)
PS: Извините, если я не указал некоторые детали, примеры кода и т. Д., Поскольку это конфиденциально. Я приложил все усилия, чтобы объяснить проблему, не ставя под угрозу политику компании.
Заранее спасибо!
1 ответ
Эта статья MSDN о диспетчеризации исключений объясняет процесс:
Когда в коде пользовательского режима возникает исключение, система использует следующий порядок поиска для поиска обработчика исключения:
- Если процесс отлаживается, система уведомляет отладчик. Для получения дополнительной информации см. Обработка исключений отладчика.
- Если процесс не отлаживается или связанный с ним отладчик не обрабатывает исключение, система пытается найти обработчик исключений на основе фреймов путем поиска фреймов стека потока, в котором произошло исключение. Система сначала ищет текущий кадр стека, а затем просматривает предыдущие кадры стека в обратном порядке.
- Если не найден ни один обработчик на основе фреймов, или нет обработчика на основе фреймов, который обрабатывает исключение, но процесс отлаживается, система уведомляет отладчик во второй раз.
- Если процесс не отлаживается или связанный с ним отладчик не обрабатывает исключение, система обеспечивает обработку по умолчанию на основе типа исключения. Для большинства исключений действием по умолчанию является вызов функции ExitProcess.
На шаге 1 исключение называется исключением первого шанса, потому что это первый шанс, который любой может поймать и обработать исключение.
На шаге 3 это же исключение называется вторым случайным исключением, поскольку во второй раз отладчик получает возможность перехватить и обработать исключение.
Только если процесс переходит к шагу 4, программа завершится сбоем или завершится. Поэтому да, только второстепенные исключения могут привести к сбою процесса.
Может ли неуправляемое исключение первого шанса вызвать сбой / перезапуск?
Смотрите раньше.
При расследовании аварии должен ли я расследовать только вторые случайные исключения?
В основном да. Это то, что все (>90%) делают при анализе сбоев.
В каких случаях мне также нужно исследовать дамп исключений первого шанса?
Случай 1:
Это второе случайное исключение может быть результатом предыдущего первого случайного исключения. Из-за этого первого случайного исключения значение может не инициализироваться и вызывать другое второе случайное исключение.
Пример кода для такого сценария:
SomeObject o = null;
try {
throw new Exception("First chance"); // consider this in some method
o = new SomeObject();
}
catch (Exception)
{
// make sure that the exception does not become a second chance exception
}
o.DoSomething(); // causes NullReferenceException first chance and second chance if uncaught
Приложение аварийно завершает работу из-за исключения NullReferenceException, но настоящей причиной является исключение ранее. Тем не менее, такие случаи, как правило, легко идентифицировать, не обращая внимания на исключения первого шанса.
Случай 2:
Исключения имеют высокие накладные расходы, то есть они стоят циклов ЦП и, следовательно, производительности. Если у вас действительно много исключений из первого шанса, вы можете избавиться от них.