记一次 Windows10 内存压缩模块 崩溃分析
一:背景
1. 讲故事
在给各位朋友免费分析 .NET程序 各种故障的同时,往往也会收到各种其他类型的dump,比如:Windows 崩溃,C++ 崩溃,Mono 崩溃,真的是啥都有,由于基础知识的相对缺乏,分析起来并不是那么的顺利,今天就聊一个 Windows 崩溃的内核dump 吧,这个 dump 是前几天有位朋友给到我的,让我帮忙看一下,有了dump之后上 windbg 分析。
二:WinDbg 分析
1. 从哪里入手
只要是 Windows 平台上的崩溃,操作系统都会维护一个 EXCEPTION_POINTERS 结构体,这个结构体的解读对分析问题非常重要,使用 !analyze -v 命令简要输出如下:
2: kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
UNEXPECTED_STORE_EXCEPTION (154)
The store component caught an unexpected exception.
Arguments:
Arg1: ffffb402b9851000, Pointer to the store context or data manager
Arg2: ffffe607bc53df30, Exception information
Arg3: 0000000000000002, Reserved
Arg4: 0000000000000000, Reserved
...
EXCEPTION_RECORD: ffffe607bc53eeb8 -- (.exr 0xffffe607bc53eeb8)
ExceptionAddress: fffff80025b04bd0 (nt!RtlDecompressBufferXpressLz+0x0000000000000050)
ExceptionCode: c0000006 (In-page I/O error)
ExceptionFlags: 00000000
NumberParameters: 3
Parameter[0]: 0000000000000000
Parameter[1]: 0000023f30ee99f0
Parameter[2]: 00000000c0000185
Inpage operation failed at 0000023f30ee99f0, due to I/O error 00000000c0000185
EXCEPTION_PARAMETER1: 0000000000000000
EXCEPTION_PARAMETER2: 0000023f30ee99f0
CONTEXT: ffffe607bc53e6f0 -- (.cxr 0xffffe607bc53e6f0)
rax=fffff80025b04b80 rbx=ffff9d808d7fa000 rcx=ffff9d808d7fa000
rdx=ffff9d808d7fa000 rsi=0000000000000002 rdi=0000023f30ee99f0
rip=fffff80025b04bd0 rsp=ffffe607bc53f0f8 rbp=0000023f30eea2fe
r8=0000023f30ee99f0 r9=0000000000000964 r10=ffff9d808d7faea0
r11=0000023f30eea354 r12=ffffe607bc53f368 r13=ffffb402d84d8000
r14=ffff9d808d7fb000 r15=0000000000000000
iopl=0 nv up ei pl zr na po nc
cs=0010 ss=0000 ds=002b es=002b fs=0053 gs=002b efl=00050246
nt!RtlDecompressBufferXpressLz+0x50:
fffff800`25b04bd0 418b08 mov ecx,dword ptr [r8] ds:002b:0000023f`30ee99f0=????????
Resetting default scope
...
从卦中信息看,是由于将地址 0000023f30ee99f0 所映射的物理内存页换入到内存中,抛了一个IO错误,从汇编指令 ecx,dword ptr [r8] ds:002b:0000023f30ee99f0=???????? 上也能看的出来。
如果大家不信,可以用 !vtop 和 !pte 观察下它们对应的物理地址和物理页号,都是找不到的。
2: kd> !vtop 0 000000006d34aca0
Amd64VtoP: Virt 000000006d34aca0, pagedir 00000003d81fb002
Amd64VtoP: PML4E 00000003d81fb002
Amd64VtoP: PML4E read error 0x8000FFFF
Virtual address 6d34aca0 translation fails, error 0x8000FFFF.
2: kd> !pte 000000006d34aca0
VA 000000006d34aca0
PXE at FFFF86432190C000 PPE at FFFF864321800008 PDE at FFFF864300001B48 PTE at FFFF860000369A50
contains 0000000000000000
contains 0000000000000000
not valid
2. 洞察异常前的线程栈
有了这个初步信息之后,接下来就来观察异常时的寄存器上下文和线程栈信息,输出如下:
2: kd> .cxr 0xffffe607bc53e6f0 ; k
rax=fffff80025b04b80 rbx=ffff9d808d7fa000 rcx=ffff9d808d7fa000
rdx=ffff9d808d7fa000 rsi=0000000000000002 rdi=0000023f30ee99f0
rip=fffff80025b04bd0 rsp=ffffe607bc53f0f8 rbp=0000023f30eea2fe
r8=0000023f30ee99f0 r9=0000000000000964 r10=ffff9d808d7faea0
r11=0000023f30eea354 r12=ffffe607bc53f368 r13=ffffb402d84d8000
r14=ffff9d808d7fb000 r15=0000000000000000
iopl=0 nv up ei pl zr na po nc
cs=0010 ss=0000 ds=002b es=002b fs=0053 gs=002b efl=00050246
nt!RtlDecompressBufferXpressLz+0x50:
fffff800`25b04bd0 418b08 mov ecx,dword ptr [r8] ds:002b:0000023f`30ee99f0=????????
*** Stack trace for last set context - .thread/.cxr resets it
# Child-SP RetAddr Call Site
00 ffffe607`bc53f0f8 fffff800`25a5bc10 nt!RtlDecompressBufferXpressLz+0x50
01 ffffe607`bc53f110 fffff800`25a5bb14 nt!RtlDecompressBufferEx+0x60
02 ffffe607`bc53f160 fffff800`25a5b9a1 nt!ST_STORE<SM_TRAITS>::StDmSinglePageCopy+0x150
03 ffffe607`bc53f220 fffff800`25b56ff0 nt!ST_STORE<SM_TRAITS>::StDmSinglePageTransfer+0xa5
04 ffffe607`bc53f270 fffff800`25b57904 nt!ST_STORE<SM_TRAITS>::StDmpSinglePageRetrieve+0x180
05 ffffe607`bc53f310 fffff800`25b57aed nt!ST_STORE<SM_TRAITS>::StDmPageRetrieve+0xc8
06 ffffe607`bc53f3c0 fffff800`25a5c071 nt!SMKM_STORE<SM_TRAITS>::SmStDirectReadIssue+0x85
07 ffffe607`bc53f440 fffff800`25aad478 nt!SMKM_STORE<SM_TRAITS>::SmStDirectReadCallout+0x21
08 ffffe607`bc53f470 fffff800`25a5cb57 nt!KeExpandKernelStackAndCalloutInternal+0x78
09 ffffe607`bc53f4e0 fffff800`25a5713c nt!SMKM_STORE<SM_TRAITS>::SmStDirectRead+0xc7
0a ffffe607`bc53f5b0 fffff800`25a56b70 nt!SMKM_STORE<SM_TRAITS>::SmStWorkItemQueue+0x1ac
0b ffffe607`bc53f600 fffff800`25b58727 nt!SMKM_STORE_MGR<SM_TRAITS>::SmIoCtxQueueWork+0xc0
0c ffffe607`bc53f690 fffff800`25b2b94b nt!SMKM_STORE_MGR<SM_TRAITS>::SmPageRead+0x167
0d ffffe607`bc53f700 fffff800`25ad1020 nt!SmPageRead+0x33
0e ffffe607`bc53f750 fffff800`25ad023d nt!MiIssueHardFaultIo+0x10c
0f ffffe607`bc53f7a0 fffff800`25a6e818 nt!MiIssueHardFault+0x29d
10 ffffe607`bc53f860 fffff800`25c0b6d8 nt!MmAccessFault+0x468
11 ffffe607`bc53fa00 00007ff8`c3089fa2 nt!KiPageFault+0x358
12 00000067`4ca7f270 00000000`00000000 0x00007ff8`c3089fa2
从卦中的调用栈信息看,代码的源头是 用户态 (0x00007ff8c3089fa2) 过来的,应该是访问用户态地址 0000023f30ee99f0 上的内容,由于对应的物理页不在内存中,触发了 nt!KiPageFault 中断,也就是 idt 表中的 0xe 号标记的 缺页中断, 输出如下:
lkd> !idt
Dumping IDT: fffff8050ce87000
00: fffff80506206400 nt!KiDivideErrorFault
...
0e: fffff80506209980 nt!KiPageFault
在缺页中断中触发了 IO 操作 MiIssueHardFaultIo 要从pagefiles 中捞页面,接下来就是页读取逻辑 SmPageRead,最后在 RtlDecompressBufferXpressLz 中引发了蓝屏。
如果心比较细的话,你会发现有一个关键词 Decompress ,对,就是解压缩,为什么换入的page还要解压缩呢? 这就是我们的突破点。
3. 为什么会解压缩
要找到这个问题的答案,需要观察下这个异常线程的详细信息,可以用 .thread 切到异常的线程上下文,再用 !thread 观察。
2: kd> .thread
Implicit thread is now ffffb402`be04a080
2: kd> !thread ffffb402`be04a080
THREAD ffffb402be04a080 Cid 0594.2228 Teb: 000000674c5b8000 Win32Thread: 0000000000000000 RUNNING on processor 2
Not impersonating
GetUlongFromAddress: unable to read from fffff8002641152c
Owning Process ffffb402b8d58080 Image: <Invalid process>
Attached Process ffffb402b984a040 Image: MemCompression
fffff78000000000: Unable to get shared data
Wait Start TickCount 649763
Context Switch Count 9 IdealProcessor: 0
ReadMemory error: Cannot get nt!KeMaximumIncrement value.
UserTime 00:00:00.000
KernelTime 00:00:00.000
Win32 Start Address 0x00007ff8c808afb0
Stack Init ffffe607bc53fb90 Current ffffe607bc53e800
Base ffffe607bc540000 Limit ffffe607bc539000 Call 0000000000000000
Priority 8 BasePriority 7 PriorityDecrement 0 IoPriority 2 PagePriority 2
Child-SP RetAddr : Args to Child : Call Site
ffffe607`bc53de78 fffff800`25d9856e : 00000000`00000154 ffffb402`b9851000 ffffe607`bc53df30 00000000`00000002 : nt!KeBugCheckEx
ffffe607`bc53de80 fffff800`25c189db : ffffb402`b9851000 ffffe607`bc53df30 ffffe607`00000002 ffffe607`bc53dfe0 : nt!SMKM_STORE<SM_TRAITS>::SmStUnhandledExceptionFilter+0x7e
ffffe607`bc53ded0 fffff800`25bcfb1f : fffff800`00000002 fffff800`258d905c ffffe607`bc539000 ffffe607`bc540000 : nt!`SMKM_STORE<SM_TRAITS>::SmStDirectReadIssue'::`1'::filt$0+0x22
ffffe607`bc53df00 fffff800`25c062ff : fffff800`258d905c ffffe607`bc53e4e0 fffff800`25bcfa80 00000000`00000000 : nt!_C_specific_handler+0x9f
...
从卦中信息看,异常线程还有一个附加的进程 ffffb402b984a040,来自于 MemCompression 模块,从名字上看所谓的 压缩解压缩 逻辑应该和它有关系,接下来到网上去搜一下,有一篇文章说的非常好: https://www.howtogeek.com/319933/what-is-memory-compression-in-windows-10/
大意:这是 Windows10 新增的一个功能,用内存压缩技术让RAM中可以存储更多的内存页,相比传统的交换到 PageFiles.sys 有更高的性能,缺点就是需要耗费一些解压缩需要的 CPU 时间。
在 Windows10 上也能窥探一二:

4. 问题解决
解决办法很简单,学 4S 店的问题解决之道,能换的就坚决不修,让朋友把 内存压缩 给关掉,这样就不走
RtlDecompressBufferXpressLz 逻辑,理论上就不会有什么问题了。

关闭之后,据朋友反馈,这几天没有崩溃了。
三:总结
分析内核态相比用户态难度要大的多,需要对操作系统以及CPU的相关知识有一个比较深度的理解,任重道远。。。
记一次 Windows10 内存压缩模块 崩溃分析的更多相关文章
- C语言中的内存压缩技术
C语言中的内存压缩技术 前言 在整个研究生阶段我都在参与一个LTE协议栈实现的项目,在这个项目中,我们利用一个自己编写的有限状态机框架将协议栈中每一层实现为一个内核模块.我们知道,在编写内核代码时需要 ...
- linux内存源码分析 - 内存压缩(同步关系)
本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 概述 最近在看内存回收,内存回收在进行同步的一些情况非常复杂,然后就想,不会内存压缩的页面迁移过程中的同步关系也 ...
- linux内存源码分析 - 内存压缩(实现流程)
本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 概述 本文章最好结合linux内存管理源码分析 - 页框分配器与linux内存源码分析 -伙伴系统(初始化和申请 ...
- 针对ASP.NET页面实时进行GZIP压缩优化的几款压缩模块的使用简介及应用测试!(附源码)
在介绍之前,先简单说一说ASP.NET服务端GZIP压缩模块的作用及工作原理,很多人编写网页的时候页面因为使用了大量的JS特效又或者放置很多大型动态广告导致了页面或脚本体积庞大,通常都会使用一些压缩工 ...
- rt-thread中动态内存分配之小内存管理模块方法的一点理解
@2019-01-18 [小记] rt-thread中动态内存分配之小内存管理模块方法的一点理解 > 内存初始化后的布局示意 lfree指向内存空闲区首地址 /** * @ingroup Sys ...
- 【转】Python之mmap内存映射模块(大文本处理)说明
[转]Python之mmap内存映射模块(大文本处理)说明 背景: 通常在UNIX下面处理文本文件的方法是sed.awk等shell命令,对于处理大文件受CPU,IO等因素影响,对服务器也有一定的压力 ...
- C#内存压缩zip文件
C#中我们使用比较多的文件压缩第三方DLL就是Ionic.Utils.Zip.dll.但是这个DLL只支持对现有文件进行压缩,而不支持内存压缩,如果需要使用内存压缩,那么有第三方DLL ICSharp ...
- 一个C语言内存管理模块的实现
C 内存管理模块的编写 C语言手动管理内存很困难,有时候很难发现内存泄漏,这两天看了一下里面有写了一个简单的内存管理模块,发现挺精巧,可以有效检测内存泄漏 原理很简单,就是把C的malloc函数分配的 ...
- 简单的内存缓存模块 - Smache
介绍 [sm]art + c[ache] = smache Smache 是一个方便的内存缓存模块,可以通过一些简单缓存策略避免无限占用更多的内存,同时确保最常用最应该被缓存的对象被缓存. GitHu ...
- 【旧文章搬运】《从PEB获取内存中模块列表》的补充
原文发表于百度空间,2008-7-26========================================================================== 继续研究PE ...
随机推荐
- Java基础知识题
在Java语言中,已知 a 为int 型,b 为 double型,c 为 float 型,d 为 char 型,则表达式 a+b*c-d/a 的 结果类型为(选一项)A.intB.doubleC.fl ...
- Shell脚本实现模拟并发及并发数控制
#!/bin/bash #by inmoonlight@163.com #下面的代码控制并发数.其实是利用令牌原理实现 #一个线程要运行,首先要拿到令牌在该代码中即read一行数据,读取不到就会暂停, ...
- Blog作业03
目录 前言 设计与分析 踩坑心得 改进建议 总结 前言 这三次作业的题目只有2道题,但是在题量减小的同时,这三次作业集的难度也相应的上去了,题目的质量很好,运用很广泛,也考验了很多的知识点.这三次的作 ...
- vue3 vue-i18n 入口文件配置报警
报警: You are running the esm-bundler build of vue-i18n. It is recommended to conf 解决: 在vue.config.js文 ...
- vue-print-nb的应用
1.cnpm i vue-print-nb 2.触发事件:v-print="printObj" 3.触发的是个对象: printObj:{ id: ...
- Python常见加密解密算法
Python爬虫常见加密解密算法 url encode加密 简介:当url地址含有中文,或者参数有中文的时候,这个算是很正常了,但是把这样的url作为参数传递的时候(最常见的callback) ,需要 ...
- Navicate 远程连接Mysql数据库
123步骤是在服务器上运行,第四步是在本机的navicate上运行 1.use mysql 2.update user set host = '%' where user = 'root' 3.flu ...
- Duplicate File Finder Pro - 重复文件查找器,给你的 Mac 清理出大量磁盘空间
重复文件查找器 Duplicate File Finder Pro 是一个实用程序,只需3次点击就能在Mac上找到重复的文件.拖放功能和尽可能多的文件夹,你想,然后按下扫描按钮.在一分钟,应用程序将给 ...
- 可视化漂亮大屏Excel表格模板 Excel漂亮美观看板 excel电视看板 excel精美数据展示看板
企业管理者喜欢大屏看板主要是因为它可以提供以下几个方面的优势: 增强企业形象:大屏看板可以将企业的信息和广告以更加生动.直观的方式呈现出来,提高企业形象和知名度. 提高工作效率:大屏看板可以在企业内部 ...
- Semantic Kernel 知多少 | 开启面向AI编程新篇章
引言 在ChatGPT 火热的当下, 即使没有上手亲自体验,想必也对ChatGPT的强大略有耳闻.当一些人在对ChatGPT犹犹豫豫之时,一些敏锐的企业主和开发者们已经急不可耐的开展基于ChatGPT ...