Delphi中的Guard页面异常?

时间:2009-04-19 10:01:16

标签: delphi exception

Raymond Chen发表了一篇文章,其中he tells how bad IsBadXxxPtr function is by eating guard page exception

我不太明白它是如何应用于Delphi的。谁和如何正常(即不调用IsBadXxxPtr)处理此异常? 我知道Delphi插入一个代码(例如)访问大型静态数组的内存 - 正是出于这个原因:扩展堆栈。

但是如果提出了防护页面异常:谁将在Delphi应用程序中处理它?我不能用不合适的方式使用try / except来意外地弄乱它吗? Delphi的调试器会通知我这些异常吗?

2 个答案:

答案 0 :(得分:14)

Windows结构化异常处理(SEH)具有两阶段结构。当发生异常时,Windows首先通过遵循已注册的异常处理程序链(其头部存储在x86上的fs:[0]中,即FS段指向的段中的第一个dword)来查找异常的处理程序。寄存器 - 所有那些丑陋的16位段偏移逻辑都没有在32位中消失,它只是变得不那么重要了。)

通过调用具有特定标志的函数来完成搜索,该标志指针存储在堆栈的每个异常帧中。 fs:[0]指向最顶层的帧。每个帧指向前一帧。最终,列表中的最后一帧是由操作系统提供的(如果未处理的异常到达,则此处理程序将弹出应用程序崩溃对话框。)

这些函数通常会检查异常的类型,并返回代码以指示要执行的操作。其中一个可以返回的代码基本上是“忽略此异常并继续”。如果Windows看到这一点,它会将指令指针重置为异常点并继续执行。另一个代码表明此异常帧应该处理给定的异常。第三个代码是“我不会抓住这个异常,继续搜索”。 Windows继续调用这些异常过滤器函数,直到找到一个以某种方式处理异常的函数。

如果Windows发现一个通过捕获它来处理异常,那么它将继续将堆栈展开回到该处理程序,该处理程序包括再次调用所有函数,仅传递不同的标志。在这一点上,函数执行finally逻辑,直到执行except逻辑的处理程序。

但是,由于堆栈页面保护异常,过程是不同的。语言的异常处理程序都不会选择处理此异常,否则堆栈增长机制会中断。相反,过滤器搜索一直过滤到OS提供的基本异常处理程序,它通过提交适当的内存来增加堆栈分配,然后返回相应的返回代码以指示操作系统应该从中断的地方继续,而不是解开堆栈。

工具和调试基础架构旨在让这些特殊异常正常播放,因此您无需担心处理它们。

您可以在Matt Pietrek's excellent article in MSJ from over a decade ago了解有关SEH的更多信息。

答案 1 :(得分:2)

通过查看评论,在我看来,“防护页面异常”混乱完全发生在内核中,并且不需要担心用户空间。

你必须记住,这篇文章是为C ++编写的,它在内存管理方面远没有Delphi那么先进。由于两个原因,未初始化的指针问题在Delphi中比在C / C ++中少得多:

  1. Delphi在编译时检查未初始化的变量,这些(无论出于何种原因)很多C编译器都会遇到问题。
  2. Delphi将其所有动态内存初始化为0,因此您没有随机堆垃圾来处理它可能看起来像一个好的指针,当它真的没有。这意味着大多数不良指针都会为您提供访问冲突,这些冲突很容易调试,而不是默默地失败和破坏内存。