Нарушение собственного доступа с приложением .NET

у нас проблема с приложением .NET. Он случайным образом при закрытии создает собственное нарушение доступа (поэтому не исключение .NET).

  • Windows Server 2012 x64 (виртуальная машина, работающая на блейд-системе)
  • .NET 4.0 Framework (установлена ​​4.5)
  • наше приложение - это приложение .NET x86 (не AnyCPU, а не ASP.NET)
  • Собственные модули сторонних производителей, использующие SQL CE 3.5 и другие.

Отчет об ошибке из журнала событий Windows выглядит примерно так (названия приложений и модулей опущены, и я перевел записи с немецкого):

Exceptioncode: 0xc0000005
Offset: 0x00006a9e
Process ID: 0xfe8
...

Я узнал, что 0xc0000005 — это нарушение прав доступа. Это также может произойти из-за исключения .NET NullReferenceException. Мы уже создали полный дамп памяти с флагом ProcDump -ma, когда окна был открыт диалог сообщения об ошибках.

Когда я открываю этот дамп, я не могу найти какие-либо загруженные модули .NET, кроме самого файла .exe. Я не являюсь экспертом в области нативного программирования и знаю только некоторые основы WinDbg.

Итак, что я сделал:

  1. Откройте дамп с помощью WinDbg
  2. Настройте путь символа с помощью

    .sympath SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols;C:\PathToMatchingPDBs\ForTheProgram
    
  3. Перезагрузить все символы с помощью

    .reload /d /f
    
    Reloading current modules
    ...*** ERROR: Symbol file could not be found.  Defaulted to export symbols for sysfer.dll - 
    ...
    
  4. ~* k выходов

    .  0  Id: 1560.19a4 Suspend: 0 Teb: ff20e000 Unfrozen
    ChildEBP RetAddr  
    0058f0e8 7744c752 ntdll!ZwWaitForMultipleObjects+0xc
    0058f26c 76d256c0 KERNELBASE!WaitForMultipleObjectsEx+0x10b
    0058f2e0 76d2586a kernel32!WerpReportFaultInternal+0x1c4
    0058f2f4 76cf7828 kernel32!WerpReportFault+0x6d
    0058f300 774d07c4 kernel32!BasepReportFault+0x19
    0058f39c 7762c11c KERNELBASE!UnhandledExceptionFilter+0x1f1
    0058f3a4 775f3334 ntdll!__RtlUserThreadStart+0x57
    0058f3b8 77691fd7 ntdll!_EH4_CallFilterFunc+0x12
    0058f3e0 77693612 ntdll!_except_handler4_common+0x8e
    0058f400 775f30f1 ntdll!_except_handler4+0x20
    0058f424 775f30c3 ntdll!ExecuteHandler2+0x26
    0058f4ec 775f2f2b ntdll!ExecuteHandler+0x24
    0058f4ec 00406a9e ntdll!KiUserExceptionDispatcher+0xf
    0058f844 7760ac69 MyProgram!COM+_Entry_Point <PERF> (MyProgram+0x6a9e)
    0058f888 7760ac3c ntdll!__RtlUserThreadStart+0x72
    0058f8a0 00000000 ntdll!_RtlUserThreadStart+0x1
    
  5. Следующая часть Я довольно не уверен, правильно ли я сделал. Я где-то читал, что можно взять адрес столбца RetAddr и передать его в uf, чтобы посмотреть, что делает функция в этот момент. Это правильно? Поэтому я ожидаю, что следующая команда отобразит дизассемблирование функции в MyProgram+0x6a9e, см. стек вызовов выше.

    >uf 0x00406a9e
    MyProgram!COM+_Entry_Point <PERF> (MyProgram +0x6a9e):
    00406a9e ff2500204000    jmp     dword ptr [MyProgram!COM+_Entry_Point <PERF> (MyProgram+0x2000) (00402000)]
    
    mscoree!_CorExeMain_Exported:
    707f4ddb 8bff            mov     edi,edi
    707f4ddd 56              push    esi
    707f4dde e80c2f0000      call    mscoree!ShellShim__CorExeMain (707f7cef)
    707f4de3 6a00            push    0
    707f4de5 8bf0            mov     esi,eax
    707f4de7 e84bc4ffff      call    mscoree!GetShimImpl (707f1237)
    707f4dec e93a800000      jmp     mscoree!_CorExeMain_Exported+0x11 (707fce2b)
    
    mscoree!_CorExeMain_Exported+0x11:
    707fce2b 83f801          cmp     eax,1
    707fce2e 750a            jne     mscoree!_CorExeMain_Exported+0x20 (707fce3a)
    
    mscoree!_CorExeMain_Exported+0x16:
    707fce30 6858378370      push    offset mscoree!g_wszShimImplDllPath (70833758)
    707fce35 e826350100      call    mscoree!DisplayMessageBoxForNoShimImpl (70810360)
    
    mscoree!_CorExeMain_Exported+0x20:
    707fce3a 8bc6            mov     eax,esi
    707fce3c 5e              pop     esi
    707fce3d c3              ret
    

    Я не уверен, как это интерпретировать. Похоже, это действительно точка входа приложения из-за CoreExeMain Exports? Так что здесь не так много полезной информации, или? Только то, что проблема возникает на уровне собственного кода; насколько я это интерпретировал.

И просто для полноты:

.loadby sos clr
Unable to find module ‘clr’
!pe
No export pe found.

Когда я открываю дамп с помощью Visual Studio, там также написано, что исключение не найдено.

Вот как далеко я продвинулся. Может быть, кто-нибудь может помочь мне интерпретировать эти данные и/или дать мне несколько советов, что еще я могу попробовать?

Мои вопросы:

  • Может ли IL-код, сгенерированный с помощью Reflection.Emit, привести к такой ошибке?
  • Что я могу сделать для дальнейшего анализа проблемы/нахождения причины?
  • Что означает COM+_Entry_Point. Является ли это основной точкой входа моего приложения или это связано с каким-то внешним компонентом?

ИЗМЕНИТЬ

@Йохен Калмбах

.ecxr;kP

Minidump doesn't have an exception context
Unable to get exception context, HRESULT 0x80004002
ChildEBP RetAddr  
0058f0e8 7744c752 ntdll!ZwWaitForMultipleObjects+0xc
0058f26c 76d256c0 KERNELBASE!WaitForMultipleObjectsEx+0x10b
0058f2e0 76d2586a kernel32!WerpReportFaultInternal+0x1c4
0058f2f4 76cf7828 kernel32!WerpReportFault+0x6d
0058f300 774d07c4 kernel32!BasepReportFault+0x19
0058f39c 7762c11c KERNELBASE!UnhandledExceptionFilter+0x1f1
0058f3a4 775f3334 ntdll!__RtlUserThreadStart+0x57
0058f3b8 77691fd7 ntdll!_EH4_CallFilterFunc+0x12
0058f3e0 77693612 ntdll!_except_handler4_common+0x8e
0058f400 775f30f1 ntdll!_except_handler4+0x20
0058f424 775f30c3 ntdll!ExecuteHandler2+0x26
0058f4ec 775f2f2b ntdll!ExecuteHandler+0x24
0058f4ec 00406a9e ntdll!KiUserExceptionDispatcher+0xf
0058f844 7760ac69 MyProgram!COM+_Entry_Point <PERF> 
0058f888 7760ac3c ntdll!__RtlUserThreadStart+0x72
0058f8a0 00000000 ntdll!_RtlUserThreadStart+0x1b

Почему минидамп?

@Томас В.

lm

start    end        module name
00400000 0040c000   MyProgram   (private pdb symbols)  c:\...\release\MyProgram.pdb
707f0000 7083a000   mscoree    (pdb symbols)          c:\symbols\mscoree.pdb\7608F9FF3C954E429A27D833164E4BEE2\mscoree.pdb
74b70000 74bdd000   sysfer     (export symbols)       sysfer.dll
76cc0000 76df0000   kernel32   (pdb symbols)          c:\symbols\wkernel32.pdb\CFACA818EC334A5EAD707CD86C847B4A1\wkernel32.pdb
77440000 774e6000   KERNELBASE   (pdb symbols)          c:\symbols\wkernelbase.pdb\CAE0056433064B78937D9022B20FA1102\wkernelbase.pdb
775b0000 77707000   ntdll      (private pdb symbols)  c:\symbols\wntdll.pdb\EC83D8DF555946E0B630133EBD9792662\wntdll.pdb

Изменить 2

Дополнительная информация:

!heap
Index   Address  Name      Debugging options enabled
  1:   009c0000                
  2:   006b0000                
  3:   00770000                
  4:   00d00000


!heap -a
Index   Address  Name      Debugging options enabled
  1:   009c0000 
    Segment at 009c0000 to 00abf000 (0000b000 bytes committed)
  2:   006b0000 
    Segment at 006b0000 to 006bf000 (00003000 bytes committed)
    Segment at 00810000 to 0090f000 (00042000 bytes committed)
  3:   00770000 
    Segment at 00770000 to 0077f000 (00003000 bytes committed)
  4:   00d00000 
    Segment at 00d00000 to 00d3f000 (00001000 bytes committed)


!heap -l
Searching the memory for potential unreachable busy blocks.
Heap 009c0000
Heap 006b0000
Heap 00770000
Heap 00d00000
Scanning VM ...
Scanning references from 204 busy blocks (0 MBytes) ...
Entry     User      Heap      Segment       Size  PrevSize  Unused    Flags
-----------------------------------------------------------------------------
006b07c0  006b07c8  006b0000  006b0000        88       220         8  busy 
007707c0  007707c8  00770000  00770000        88       220         8  busy 
2 potential unreachable blocks were detected.

Так что это значит?


person Daniel Bişar    schedule 22.05.2014    source источник
comment
Если у вас есть исключение, вы должны выполнить .ecxr;kP; и/или !analyze -v!   -  person Jochen Kalmbach    schedule 22.05.2014
comment
Вы просто летите вслепую. Обратите внимание на аннотацию MyProgram+0x6a9e, где произошел сбой. Смещение +0x6a9e очень-очень далеко от любого известного места в вашей программе. Вы получаете хорошие небольшие смещения для функций операционной системы, вы получаете для них хорошие PDB с сервера Microsoft Symbol. У вас нет PDB для вашей собственной программы, отладчик просто не может сказать вам ничего полезного. Очень важно организовать это, ваш сервер сборки должен сохранять PDB, чтобы вы могли использовать их позже, когда вы получите мини-дамп.   -  person Hans Passant    schedule 23.05.2014
comment
Я использую свои собственные PDB. Видеть стек вызовов MyProgram!COM+_Entry_Point без их загрузки там было написано MyProgram!+0x6a9e   -  person Daniel Bişar    schedule 23.05.2014
comment
Удалось ли вам создать новый дамп с помощью ProcDump с предложенными мной настройками или WER LocalDumps? Я думаю, что мы смотрим здесь не на то.   -  person Thomas Weller    schedule 27.05.2014
comment
Там ошибка больше не повторялась до сих пор...   -  person Daniel Bişar    schedule 27.05.2014
comment
Итак, некоторое время назад проблема заключалась в sysfer.dll, принадлежащем Symantec Firewall/Antivirus. Отключите эту программу и все будет хорошо.   -  person Daniel Bişar    schedule 23.04.2015


Ответы (2)


Это еще не совсем ответ, но слишком длинный для комментария. В порядке появления:

«когда диалоговое окно отчетов об ошибках Windows было открыто».

Создание аварийного дампа, когда отчеты об ошибках Windows уже работают с процессом, не очень хорошо работает. Вместо этого запустите приложение напрямую с помощью ProcDump:

procdump -e -ma -x c:\MyDump.dmp C:\PathTo\MyApplication.exe Arguments

Затем ProcDump создаст аварийный дамп при возникновении исключения. Если это вас не устраивает, позвольте службе отчетов об ошибках Windows сохранить дамп на диск. См. Сбор дампов пользовательского режима для настроек реестра. Обязательно установите DumpType на 2 для .NET.

«Я не могу найти загруженные модули .NET»

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

"Настройте путь символа с..."

Это нормально. Если вы не хотите вводить весь этот HTTP-материал, вы также можете использовать

.symfix C:\Symbols
.sympath+ C:\PathToMatchingPDBs\ForTheProgram

"~* k выводит KERNELBASE!UnhandledExceptionFilter+0x1f1"

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

"Не удалось найти модуль "clr""

Вы уверены, что это приложение .NET 4? Попробуйте .loadby sos mscorwks, чтобы узнать, является ли это .NET 2. Если и это не поможет, проверьте lm m ms* для других .NET-подобных сборок.

person Thomas Weller    schedule 22.05.2014
comment
WER может разрешать локальные аварийные дампы (как вы сказали во второй теме). Вам нужно только настроить его в реестре. Это лучшая функция, которую я когда-либо видел, чтобы говорить о аварийных дампах без запуска специальных процессов! Он работает с Vista SP1 и более поздними версиями... это мой рекомендуемый способ создания аварийных дампов: msdn.microsoft.com/en-us/library/windows/desktop/bb787181 - person Jochen Kalmbach; 22.05.2014
comment
lm m * перечисляет только c:\symbols\mscoree.pdb\7608F9FF3C954E429A27D833164E4BEE2\mscoree.pdb. Да, я уверен, что это приложение .NET 4. Мне также очень интересно, что в дампе нет информации, связанной с .NET. Кажется, я не могу использовать пользовательские дампы, потому что в MSDN указано: приложения, которые создают свои собственные отчеты о сбоях, включая приложения .NET, не поддерживаются этой функцией. - person Daniel Bişar; 23.05.2014
comment
Начиная с .NET 4, кажется, вы также можете использовать раздел реестра. Я попробую это. - person Daniel Bişar; 23.05.2014

загрузите дамп в windbg и выполните !analyze -v, если символы правильные, вы должны получить
точный результат, включая исходные строки

взяв обратный адрес и скормив его uf, ничего полезного не получится

uf выполняет поток управления, и если return address points to a jmp to some random function в какой-то случайной dll uf will simply dump the random function .

return address is pushed into the stack by the callee

если вы сделаете ub <return address>, вы сможете найти callee

должно быть что-то вроде call blah <0x.......>

теперь выполните uf on the callee uf <0x........>, чтобы увидеть, что делает вызов
скорее всего, он выглядит так, как будто он выполняет необработанное исключение

person blabb    schedule 26.05.2014