Windows Phone App的dump文件实例分析- System.ExecutionEngineException

前言

在开始这篇文章之前我们先来讲讲如何从高度优化的Release版的Dump中找到正确的异常上下文地址,并手动恢复异常发生的第一现场。

1. 什么是异常上下文

简单来说,在windows体系的操作系统里面,每个线程都有自己的线程上下文来保存需要的信息,其中包括当前寄存器的值。我们这里需要找到的异常上下文就是当异常发生的时候,异常分发器帮我们保存的当前寄存器的值(也叫寄存器上下文),利用这些信息结合汇编代码的分析,我们就可以进一步找到发生异常的原因。关于寄存器上下文结构体的定义我们可以在winnt.h找到,这里就不一一解释了。

2. Windbg 中的“.cxr + Context Address”命令可以帮助我们恢复异常发生时候寄存器的一手资料,那么我们只需要找到这个上下文的地址就可以交由这个命令来处理了。

3. 如何找到保存上下文的地址?

当我们使用windbg打开dump file的时候,我们都会看到类似下面的调用堆栈模式:

这个正式异常分发器在帮助我们保存上下文,我们看看RtlDispatchException的函数声明,这里使用”x”命令:

大家已经发现了,这个函数的第二个参数正是我们要找的上下文地址。

4. 有了这个上下文地址,我们就可以使用”.cxr ”命令进行恢复了。这里第二个参数是00c2e168, 执行”.cxr 00c2e168”命令。

5. 这个值真的对吗?恢复了异常发生时的上下文,让我们再看看调用堆栈的变化

这个堆栈和寄存器的的值看起来太诡异了,这不禁让我们对上面的地址产生了怀疑!

6. 想想看,这个dump文件来自于Release版本的App,编译器会在生成release版的可执行文件中进行大量的优化,这种情况下的函数调用会最大程度地使用我们的寄存器来传递参数,而不是靠@esp+0x?来进行。想到了这里,让我们再次回到RtlDispatchException去查看一下。

7. 使用”.frame + index”跳转到调用堆栈中指定的栈帧,并使用”dv”命令查看本地变量

这次我们清晰的看到了寄存器r6和r9里面的内容,正是代码优化的结果。编译器优化了代码使用r6, r9两个寄存器来代替“栈操作”进行了传参。

8. 再次使用”.cxr” 和”k”,这次我们就看到了真正的异常发生第一现场

原来是ldr指令企图加载一个空地址引发了遭难。

现在我们已经学会了如何在高度优化的release版本中分辨出正确的上下文地址,接下来我们继续查找程序奔溃的原因。

定位异常上下文

1. 我们找到了真正的异常上下文,先看来看一下这个调用堆栈。

2. 让我们来看看FontFileReference::ReleaseFragment到底干了些什么,使用命令”uf 模块名字!函数名字“来反编译这个函数。

3. 再次查看这个函数对应的栈帧里面的内容来辅助我们理解上面的汇编代码,”.frame + frame index”

4. 使用命令”dt 模块名字!类名字”来查看FontFileReference的内存布局

分析和推测

1. 从调用堆栈可以看到,下面的语句触发了异常,这里的指令正在执行加载寄存器的操作,load r3寄存器里面存的地址,但是r3=0,我们不禁要问,r3为什么会是0,而这个r3里面又应该是什么呢?

2. 重点分析寄存器,r3。这里给大家分享个看汇编指令的心得,其实我们并不用每次都一行一行的来分析,简单的方法就是找到关键的指令!在这个case里面,我把下面的指令列为关键指令:

为什么要把这几行列为关键指令呢?这是因为这里出现了”r0, #0x10”和blx。这里的”r0, #0x10”是”r0 + 0x10“的意思,”blx” 是调用子函数的意思。再结合FontFileReference这个类的结构,我们可以合理的猜测到r0里面的地址应该指向了this指针,那么r0 + 0x10就是FontFileReference这个类里的成员变量”stream_”。

我们已经知道了r0里面的是this指针,r3里面的是指向类型为ComPtr<IDWriteFontFileStream>的COM对象stream_,那么接下来r3+0x10又是什么呢,关于IDWriteFontFileStream的定义可以在dwrite.h中查到也可以使用”dt /v”显示出来。

我们知道从IUnknown继承下来的COM接口前三个函数一定是QueryInterfacy,Release和AddRef,那么r3+0x10就是ReleaseFileFragment这个函数了。布局大致如下:

在这里需要解释一下为什么我们要进行“猜测”而不是直接调用”dt this”命令来直接查看当前的这个FontFileReference对象呢?因为这个dump是release版本产生的,很多的信息都已经无效了:

3. 经过上面的分析我们就知道了这段汇编代码的主要工作就是调用” stream_->ReleaseFileFragement”。对比”!analyze –v” 命令给出的信息可以验证我们的猜测并得出结论,正是 stream_这个变量为空导致了异常。再来看看这个线程堆里面还有什么有用的信息:

分析和定位我们的源代码

栈里面残留的信息也把问题指向了Font,FontFamily相关的内容,从native的callstack中我们没法定位到我们的代码,这里使用”!CLRStack”命令来看看我们CLR的代码栈里面的调用信息:

红线的代码就是我们自己的代码了,好了打开代码查看一下:

从这段代码看我们在动态创建TextBlock的时候确实没有指定FontFamily这个属性。程序员在开发代码和测试的时候这个异常并没有出现,从我们下载下来的excel文件来看,这个异常只出现在WP8.0平台,30天内导致的闪退累计次数是4000次。这个次数相比我们APP的活跃度来说非常小。所以我们可以推断,这个bug应该是系统的问题,很可能是stream_这个COM对象的ref count增减操作在没有指定FontFamily的一些特殊情况下发生的,它导致了stream_被提前释放掉了。既然是系统的问题,那我们能做什么呢?首先,我们可以指定一个FontFamily给控件TextBlock;其次,在CreateWideTileBackgroundImage这个函数里面的Render调用上添加try catch来捕获这个“System.ExecutionEngineException“。

小结

虽然有些时候问题是由系统引起的,但是通过分析我们还是可以采取一定的措施在我们的代码里面来处理的。

时间: 2024-10-04 00:39:40

Windows Phone App的dump文件实例分析- System.ExecutionEngineException的相关文章

Windows Phone App的dump文件实例分析-Stack Overflow

前言 这篇文章我们一起来分析一个从Windows Phone Dev Center上下载下来的dump file.首先按照我上一篇的步骤设置好我们的Windbg,并按住Ctrl +D打开dumpfile.可以看到下面的界面: 分析一个dump file可以分解为4个步骤,第一步是信息收集,第二步是定位异常上下文,第三步分析和推理出现问题的原因,第四步分析和定位我们的源代码并进行修复和验证. 信息收集 我们可以使用一些命令浏览一下这个dump file对应的系统版本和一些模块的信息辅助我们后面的分

Windows Phone App的dump 文件分析

前言 我们在发布了自己的App以后,Windows Phone的Error Report机制会帮助我们收集程序的崩溃信息并发送到微软的服务器上,这可以辅助开发者提高App的稳定性. 那么如何利用这些dump file呢?首先我们需要下载这些dump file从微软开发者网站,然后借助调试工具进行分析,我们这里选用Windbg. 下载步骤 1. 登录http://dev.windows.com/en-us/dashboard 2. 选择Windows Phone Store 3. 进入Report

HTTP的上传文件实例分析

HTTP的上传文件实例分析 由于论坛不支持Word写文章发帖. 首先就是附件发送怎么搞,这个必须解决.论坛是php的.我用Chrome类浏览器跟踪请求,但是上传的文件流怎么发过去没找到,估计流可能多或者什么的不好显示,只知道发送了文件名字.需要实际了解下post文件,不能只会后台或界面不了解前台数据处理和协议怎么传送数据. 图中:有些相关文章 HTTP请求中的form data和request payload的区别 AJAX POST请求中参数以form data和request payload

ADPLUS使用配置文件设置断点时无法创建DUMP文件原因分析

ADPLUS简介 ADPLUS.vbs是Debugging Tool for Windows里带的一个VBS脚本.我们可以用它很方便地生成进程的内存转储文件.从Debugging Tool for Windows版本6.12.2.633后,ADPLUS.vbs被ADPLUS.EXE所替代.原有的VBS脚本更名为adplus_old.vbs. 背景 在一台服务器上,ASP.NET出现随机崩溃的情况.为了解决这个问题,我们决定用ADPLUS收集dump. 我们使用如下配置文件: <ADPlus Ve

[JAVA]JAVA章3 如何获取及查看DUMP文件

一.dump基本概念 在故障定位(尤其是out of memory)和性能分析的时候,经常会用到一些文件来帮助我们排除代码问题.这些文件记录了JVM运行期间的内存占用.线程执行等情况,这就是我们常说的dump文件.常用的有heap dump和thread dump(也叫javacore,或java dump).我们可以这么理解:heap dump记录内存信息的,thread dump是记录CPU信息的. heap dump: heap dump文件是一个二进制文件,它保存了某一时刻JVM堆中对象

dump文件解析之探索.Net的内存

前言: 对于需要长时间运行的.net程序,有时需要我们查看内存的使用有没有内存泄露问题. 我们可以从dump文件中找到答案. Dump的看点 用dump文件来分析内存,到底我们需要关心哪些点呢? 内存的使用情况 HeapSize/object的数量 也就是托管堆使用大小以及托管堆内有多少数量的对象 1.1  查看有没有存在有占用大量内存的对象 <比如有某类下面的一个集合>  1.2  0 1 2各代的size<查看各代的内存是否有异常> 2.调查是否有内存泄露(重点) 2.1  查

使用jprofiler分析dump文件一个实例

1.. jstact 命令先分析一下 一次fullgc之后 old 老年代使用比例 只降低2% 应该有什么大的对象常驻内存. 2.可以使用jmap 命令查看对象大小 (这里后面使用jprofiler 就没用这个命令) jmap -histo:live 72947 | more 3 .dump 线上文件栈 [[email protected] ~]# jmap -dump:live,format=b,file=heap201712.hropf  72947   Dumping heap to /r

.NET对象与Windows句柄(三):句柄泄露实例分析

在上篇文章.NET对象与Windows句柄(二):句柄分类和.NET句柄泄露的例子中,我们有一个句柄泄露的例子.例子中多次创建和Dispose了DataReceiver和DataAnalyzer对象,但由于忘记调用DataAnalyzer的Stop方法,导致产生句柄泄露.本文假定我们已经发现了泄露现象但还不知道原因,讨论如何在这种情况下分析问题. 一.发现问题 在程序运行约一个小时以后,通过任务管理器发现句柄数超过5000,线程数也超过1000.对于一段只需要并行接收和分析数据的简易代码来说,这

蓝屏 Dump文件分析方法

WinDbg使用有点麻烦,还要符号表什么的.试了下,感觉显示很乱,分析的也不够全面... 试试其他的吧!今天电脑蓝屏了,就使用其dump文件测试,如下: 1.首先,最详细的,要属Osr Online这个在线分析网站了: 打开其分析地址:http://www.osronline.com/page.cfm?name=analyze 下拉,找到上传按钮(上图),将需要分析的dump文件浏览上传即可...dump文件一般在C:\www\minidump下 分析完成后生成的内容非常多: 主要看第一个Pri