第五节MemoryCorruption.doc

  1. 1、本文档共50页,可阅读全部内容。
  2. 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
  3. 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  4. 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
第五章Memory Corruption 第一部分:堆栈 有两个原因导致内存破坏成为最棘手的程序出错类型之一。首先,破坏的源头和现象可能相隔很远,很难将原因和结果关联起来。其次是由于只有在比较罕见的条件下症状才显露出来,使得要一致的重现错误比较困难。 原则上只要满足以下两个条件中的任意一个,就会发生内存破坏。 线程对一块不属于它的内存进行写操作。 线程对属于它自己的内存进行写操作时,破坏了该内存的状态。 这里有个小程序可以作为展示第一个条件的例子。 #include windows.h #define BAD_ADDRESS 0xBAADF00D int __cdecl wmain (int argc, wchar_t* pArgs[]) { char* p =(char*)BAD_ADDRESS; *p = ’A’; return 0; } 上面的小程序先声明了一个char型指针,然后对其初始化,赋给其一个不可访问的地址(0xBAADF00D)。运行该程序的最终结果就是程序崩溃,紧接着弹出可怕的Dr.Watson(译注)。很明显这是因为这个小程序中执行了一次无效的内存访问导致,但是在很复杂的系统中要指出错误很麻烦。例如应用程序分配了一块内存,并且计划了其生命周期。如果过早的释放了它,失效的指针访问就会导致内存破坏。应用程序对不属于自己的内存进行写访问会导致程序崩溃,这是最好的情况。等等!!读者看到这里可能会问:你是说程序崩溃是最好的情况?!没错,对于内存破坏来说,发生崩溃的话也许能立即指明发生内存破坏的原因。就像上面的小程序一样,由于被写的内存无效,所以立即发生了崩溃。这是个好消息,因为我们很轻松的就看到了错误原因:一个指针指向了无效的内存地址。再看看第2种情况,如果无效指针指向的是属于程序中别的部分分配的内存的话,可能出现如下几种症状: 程序崩溃:跟前面的程序崩溃的主要区别在于发生的时间会延后一些。上面的示例程序因为尝试写一块被操作系统认为无效的内存导致了崩溃。第2种情况下,应用程序尝试写入的是操作系统认为有效的内存,所以允许其写入,没有错误发生。随后应用程序可能会试着使用被错误改写过的内存,也许就会崩溃(依赖于内存访问的性质)。 不会崩溃,但是有意料之外的行为:由于之前写了无效数据到其他部分所拥有的内存中,不一定程序就会崩溃。这种情况相当多。应用程序的其他部分会继续使用被写入异常数据的内存,甚至内存的状态都已经被修改过(通常情况下不会发生这种状况)。看个例子,假设有个线程池的类,除了能对线程池的请求排队外,还有个方法用于设置一个标志以控制流程结束。线程池周期性的检查该标志,一旦发现该标志为TRUE则停止工作。应用程序会初始化出该线程池的一个单体对象来使用。现在假设线程池正在处理200个请求(信用卡授权)时,一个线程错误的将标志设置为TRUE了。于是线程池突然间就停止工作,客户在用信用卡交易时发生错误,电话铺天盖地的响起来……这是典型的内存破坏的例子:线程破坏内存最终导致发生不可预料的行为。由于修改内存的线程已经对内存数据造成了损害,随后使用这块内存有时(通常总是)无法预料。要找到这些类型的内存破坏的根源那是相当的难啊。 译注: 内存破坏诊断流程 本节讲述一下内存破坏问题的处理流程。下面的流程图简单描述了每一个步骤。有一点很重要:要找到内存破坏问题的根源,对于不同的状况,可能需要反复执行Figure 5.1中的流程才行。 Figure 5.1 内存破坏分析过程 步骤1:状态分析 在开始研究内存破坏的问题前,首先应该确保你当前发现到的错误确实是因为内存破坏的缘故导致的。这个步骤还可以进一步分解,如Figure 5.2 Figure 5.2 状态分析过程 如同前面提到的,内存破坏的特征无非就是这两种:程序崩溃或者不崩溃但是行为异常。最开始可以通过分析被破坏的内存的状态来对其行为进行初步的分析。那么我们如何知道要分析哪些状态呢?随着程序崩溃,寻找起点就(译注:这里的起点应该是指代码中程序崩溃的位置吧)十分简单了。由于一些未预期的状态导致程序中的代码执行崩溃,而在崩溃的时候的代码是已知的。通过观察程序发生崩溃时的内存状态以及对相关代码的检视,我们可以对原始状态作出准确的判断。“没问题”,尽管问题多多,但是代码执行路径可以产生当前状态。如果你遇到的是这种情况,就其本身而言,这不是内存破坏问题,但仍可能是由于未预期的代码执行路径写内存错误。然而,如果没有代码执行路径能令内存变成当前状态,唯一貌似可能的解释就是发生了内存破坏,内存被改写了。 如果你遇到的不是应用程序崩溃,而是发生周期性的奇特行为的话,要找到被偷偷破坏的内存可就没程序崩溃时那么简单明了。一般来说,当程序发生异常行为时,你最好用调试器中断程序以进

文档评论(0)

0520 + 关注
实名认证
内容提供者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档