(No Ratings Yet)
Всем привет. Сегодня мы рассмотрим еще одну проблему, которая может возникать в коде Kernel Mode и которая связана с утечкой памяти. Мы все понимаем, что такое утечка памяти (это когда код выделяет память а обратно системе ее не возвращает), более того, в большинстве программ написанных с использованием технологий не предусматривающих автоматическую сборку мусора (н-р С/С++) эти утечки встречаются довольно часто. К сожалению это характерно и для систем, который предусматривают автоматическую сборку мусора (С#, Java например), особенно если эти приложения являются серверными.
Чтобы этой проблемы не было, требуется более профессиональный подход в написании кода, дополнительное тестирование (или же дополнительные планки памяти, шутка :)). Для стационарных ПК проблема всегда решается просто, перегрузил и работай по новой, но с серверами, который работают в режиме 24 часа в сутки, все может быть намного сложней и требует вмешательства администраторов.
Что же происходит при утечке в памяти ядра? Как мы знаем, код, который работает в Kernel Mode использует 2-а типа памяти:
Для выделения и освобождения памяти используются функции семейства ExAllocatePool
Для освобождения – семейства ExFree
Более детальную информацию об этих функциях смотрите на MSDN.
При нехватке памяти в одном из этих пулов, происходит BSOD, при этом здесь могут быть разные варианты (в зависимости от версии ОС, установленных драйверов). Почему так? Потому что, какой-то драйвер стороннего производителя может в своем коде не предусматривать тот вариант, что возникает проблем с выделением памяти и работать дальше.
Давайте рассмотрим пример, берем NotMyFoult Руссиновича, которую мы уже не раз обсуждали и пытаемся вызывать крах систем в подкачиваемой памяти (выбираем Leak / Leak Paged).
Устанавливаем 10 Мбайт в сек, чтобы долго не ждать.
Vista x86 (без сторонних драйверов) упорно продолжала держаться, хотя посмотрите на скриншот ниже, все уже и не работало как нужно. Я за час работы так и не дождался краха.
Хорошо, перезапускаем виртуальную рабочую станцию и выбираем утечку памяти в NonPaged Pool.
Через время возникает BSOD 0x000000A5 — ACPI_BIOS_ERROR
Давайте выполним анализ дампа краха.
************* Symbol Path validation summary ************** Response Time (ms) Location Deferred srv*C:Symbols*http://msdl.microsoft.com/download/symbols Symbol search path is: srv*C:Symbols*http://msdl.microsoft.com/download/symbols Executable search path is: Windows Server 2008/Windows Vista Kernel Version 6002 (Service Pack 2) UP Free x86 compatible Product: WinNt, suite: TerminalServer SingleUserTS Built by: 6002.18005.x86fre.lh_sp2rtm.090410-1830 Machine Name: Kernel base = 0x81a11000 PsLoadedModuleList = 0x81b28c70 Debug session time: Thu Aug 13 13:09:12.276 2015 (UTC + 3:00) System Uptime: 0 days 0:05:42.933 Loading Kernel Symbols ............................................................... ................................................................ ......................... Loading User Symbols Loading unloaded module list .... ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* Use !analyze -v to get detailed debugging information. BugCheck A5, {3, 0, c000009a, 0} Probably caused by : Unknown_Image ( ANALYSIS_INCONCLUSIVE ) Followup: MachineOwner --------- kd> !analyze -v ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* ACPI_BIOS_ERROR (a5) The ACPI Bios in the system is not fully compliant with the ACPI specification. The first value indicates where the incompatibility lies: This bug check covers a great variety of ACPI problems. If a kernel debugger is attached, use "!analyze -v". This command will analyze the precise problem, and display whatever information is most useful for debugging the specific error. Arguments: Arg1: 00000003, ACPI_FAILED_MUST_SUCCEED_METHOD ACPI tried to run a control method while creating device extensions to represent the ACPI namespace, but this control method failed. Arg2: 00000000, The ACPI Object that was being run Arg3: c000009a, return value from the interpreter Arg4: 00000000, Name of the control method (in ULONG format) Debugging Details: ------------------ ACPI_OBJECT: 00000000 BUGCHECK_STR: 0xA5_ACPI_STATUS_INSUFFICIENT_RESOURCES CUSTOMER_CRASH_COUNT: 2 DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT PROCESS_NAME: System CURRENT_IRQL: 2 ANALYSIS_VERSION: 6.3.9600.17298 (debuggers(dbg).141024-1500) amd64fre DPC_STACK_BASE: FFFFFFFF8039E000 STACK_TEXT: 8039df0c 8069141f 000000a5 00000003 00000000 nt!KeBugCheckEx+0x1e 8039df28 80692053 00000000 c000009a 00000000 acpi!ACPIBuildCompleteMustSucceed+0x33 8039df4c 80692608 00000000 81ab7a00 806b9ce0 acpi!ACPIBuildProcessDevicePhaseAdrOrHid+0xef 8039df70 80693260 806b9d30 806b7030 806b9ce0 acpi!ACPIBuildProcessGenericList+0x52 8039df88 81abb6a2 806b9ce0 00000000 00000000 acpi!ACPIBuildDeviceDpc+0xca 8039dff4 81ab92d5 8453e8b0 00000000 00000000 nt!KiRetireDpcList+0x147 8453e8cc 81dd1668 806b9d02 00000000 85f7cad8 nt!KiDispatchInterrupt+0x45 8453e8e8 81dd170c 81dcde00 806b9d00 8453e914 hal!HalpCheckForSoftwareInterrupt+0x64 8453e8f8 81dcdf6b 80692fb7 806b9b60 86abfcb8 hal!KfLowerIrql+0x64 8453e8fc 80692fb7 806b9b60 86abfcb8 00000000 hal!KfReleaseSpinLock+0xb 8453e914 806bbee3 86abfcb8 80691a40 8453e934 acpi!ACPIBuildSpecialSynchronizationRequest+0xf3 8453e944 806962da 86abfcb8 00000000 8453e9cc acpi!ACPIBuildFlushQueue+0x2d 8453e988 806bc64d 85f7bcb8 8453e9cc 00000000 acpi!ACPIDetectPdoDevices+0x92 8453e9a0 806bce74 85f7bcb8 d6644f68 8453e9cc acpi!ACPIBusIrpQueryBusRelations+0x2b 8453e9c0 80698e67 85f7bcb8 00000000 85f7bcb8 acpi!ACPIBusIrpQueryDeviceRelations+0x52 8453e9f0 81cf36be 85f7bcb8 86abfcb8 d6644ffc acpi!ACPIDispatchIrp+0xff 8453ea14 81a5592d d6644fd8 8453ea90 85f7bcb8 nt!IovCallDriver+0x23f 8453ea28 81b763ad 00000000 85f7bcb8 8a630ce8 nt!IofCallDriver+0x1b 8453ea44 81b762e3 8453ea6c 81a1db6e 8a630ce8 nt!PnpAsynchronousCall+0x96 8453ea94 81b7607a 00000000 81a1db6e 8a630ce8 nt!PnpQueryDeviceRelations+0x9b 8453ead8 81b72be2 8a630ce8 00000000 97d756b0 nt!PipEnumerateDevice+0x102 8453ecd4 81b7af31 85f7cea8 97d756b0 8453ed00 nt!PipProcessDevNodeTree+0x317 8453ed08 81a1d6d2 81b1313c 8318ed78 81b43520 nt!PiProcessReenumeration+0x5d 8453ed44 81ab6e22 00000000 00000000 8318ed78 nt!PnpDeviceActionWorker+0x1e7 8453ed7c 81be6c42 00000000 5b903ef3 00000000 nt!ExpWorkerThread+0xfd 8453edc0 81a4fefe 81ab6d25 00000001 00000000 nt!PspSystemThreadStartup+0x9d 00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16 STACK_COMMAND: kb SYMBOL_NAME: ANALYSIS_INCONCLUSIVE FOLLOWUP_NAME: MachineOwner MODULE_NAME: Unknown_Module IMAGE_NAME: Unknown_Image DEBUG_FLR_IMAGE_TIMESTAMP: 0 IMAGE_VERSION: FAILURE_BUCKET_ID: 0xA5_ACPI_STATUS_INSUFFICIENT_RESOURCES_ANALYSIS_INCONCLUSIVE BUCKET_ID: 0xA5_ACPI_STATUS_INSUFFICIENT_RESOURCES_ANALYSIS_INCONCLUSIVE ANALYSIS_SOURCE: KM FAILURE_ID_HASH_STRING: km:0xa5_acpi_status_insufficient_resources_analysis_inconclusive FAILURE_ID_HASH: {a4542cfc-871a-ff92-6ff2-f09e0216672f} Followup: MachineOwner
По начальному анализу сложно понять, что у нас за проблема. Кроме того, мы делаем все это на виртуалке, она тоже может вносить свою лепту в то, какой будет стоп код.
Давайте выполним проверку состояния памяти на момент краха. Для этого используется расширение:
!poolused
Однако у меня так ничего и не получилось с отображением данных по пулах. Поэтому переходим на реальный Windows 8 (не на виртуальной рабочей станции). На реальной Windows 8 в итоге были очень большие тормоза в работе системе, но краха не было.
Теперь проверяем Windows XP SP3 на виртуалке. Опять дикие тормоза в ОС, но система без BSOD-а.
Таким образом утечка памяти в ядре один раз вызвала BSOD — ACPI_BIOS_ERROR (a5). В остальных случаях ОС практически не реагировала на действия пользователя.