内存损坏是常见的驱动程序问题。 驱动程序错误可能会导致在发生错误很久之后仍发生系统崩溃。 最常见的错误是访问已释放的内存,并分配 n 个字节,然后访问 n+1 个字节。
若要检测内存损坏,驱动程序验证程序可以从特殊池分配驱动程序内存,并监视该池是否存在不正确的访问。 为内核模式系统提供的例程(如 ExAllocatePoolWithTag )以及 GDI 系统提供的例程(如 EngAllocMem)提供了特殊的池支持。
特殊池(按对齐方式)
有两种特殊池的对齐方式可用:
- 验证开始对齐方式更好地检测未预期的提前访问。
- 验证结束对齐方式更好地检测访问溢出。
有关如何使用 “验证开始 ”和 “验证结束 ”选项的详细信息,请参阅 检测溢出和不足。 请注意,绝大多数内存损坏是由于 溢出,而不是不足。
当特殊池功能处于活动状态并且已选择 “验证结束 ”时,驱动程序请求的每个内存分配将放在单独的页面上。 返回允许分配在页面上容纳的最高地址,以便内存与页面末尾对齐。 页面的上一部分是使用特殊模式编写的。 上一页和下一页标记为不可访问。
如果驱动程序在分配结束时尝试访问内存,驱动程序验证程序将立即检测到此情况,并将发出 bug 检查0xCD。 如果驱动程序在缓冲区开头之前在内存中写入,这将(大概)更改模式。 释放缓冲区后,驱动程序验证程序将检测更改并发出 bug 检查0xC1。
如果驱动程序在释放缓冲区后读取或写入缓冲区,驱动程序验证程序将发出 bug 检查0xCC。
选择 “验证开始 ”时,内存缓冲区与页面的开头对齐。 使用此设置时,内存欠载会立即导致 bug 检查,而内存超载会在内存释放时导致 bug 检查。 否则,此选项与 “验证结束 ”选项相同。
验证结束 是默认对齐方式,因为溢出错误在驱动程序中比欠载错误更常见。
单个内存分配可以通过调用 ExAllocatePoolWithTagPriority 和 Priority 参数设置为 XxxSpecialPoolOverrun 或 XxxSpecialPoolUnderrun 来替代这些设置并选择其对齐方式。 (此例程无法激活或停用特殊池功能,或者请求特殊池进行内存分配,否则将从普通池分配。只能从此例程控制对齐方式。
在 Windows 7 及更高版本的 Windows作系统中,特殊池选项支持使用以下内核 API 分配的内存:
IoAllocateIrp 和其他可以分配 I/O 请求数据包(IRP)数据结构的例程
RtlAnsiStringToUnicodeString 和其他运行时库 (RTL) 字符串例程
根据池标记或分配大小分类的特殊池
除了驱动程序验证程序的特殊池功能(请求指定 驱动程序分配的特殊池)外,还有两种方法可以使用特殊池:
池标记。 请求为所有具有指定池标记的分配使用特殊池。
大小。 请求为指定大小范围内的所有分配申请特殊内存池。
若要请求池标记或大小范围的特殊池,请使用 Gflags,该工具包含在 Windows 调试工具中。 有关详细信息,请参阅 “使用全局标志实用工具”。
可以同时使用驱动程序验证程序的特殊池功能和 Gflags 的特殊池功能。 如果这样做,请记住,特殊池的容量是有限的,不是所有尝试从特殊池分配内存的操作都会成功,并且对于由于常规内存池中的分配而被满足的失败尝试,Windows 会返回成功状态。
特殊池效率
并非所有特殊池请求都得到满足。 特殊池中的每次分配使用一页不可分页的物理内存和两页虚拟地址空间。 如果池已用尽,则会以标准方式分配内存,直到特殊池再次可用。 从标准池填充特殊池请求时,请求函数不会返回错误,因为池请求已成功。 因此,如果激活了特殊池功能,则不建议同时验证多个驱动程序。
发出许多小型内存请求的单个驱动程序也可能会耗尽此池。 如果发生这种情况,最好为驱动程序的内存分配分配池标记,并将特殊池一次专用于一个池标记。
特殊池的大小随系统上的物理内存量增加:理想情况下,这应至少为 1 GB(GB)。 在 x86 计算机上,由于使用虚拟(除了物理)空间,因此不使用 /3GB 启动选项。 最好将页面文件的最小/最大数量增加到原来的两到三倍。
为了确保测试所有驱动程序的分配,建议在较长时间内强调驱动程序。
监视特殊池
可以监视与池分配相关的统计信息。 驱动程序验证程序管理器、Verifier.exe 命令行或日志文件可以显示这些属性。 有关详细信息,请参阅监视全局计数器。
如果 特殊池池分配成功计数器 等于 池分配成功计数器,则说明特殊池已足以涵盖所有内存分配。 如果之前的计数器低于后计数器,则意味着特殊池至少已耗尽一次。
这些计数器不会跟踪大小为一页或更大的内存分配,因为特殊内存池不适用于它们。
如果启用了特殊池功能,但已从特殊池分配的所有池分配中少于 95 个%,驱动程序验证程序管理器中会显示警告。 在 Windows 2000 中,此警告将显示在 “驱动程序状态 ”屏幕上。 在 Windows XP 及更高版本中,此警告将显示在 “全局计数器 ”屏幕上。 如果发生这种情况,则应验证较短的驱动程序列表、按池标记验证单个池,或向系统添加更多物理内存。
内核调试器扩展 !verifier 也可用于监控特殊池的使用。 它提供与驱动程序验证程序管理器类似的信息。 有关调试器扩展的信息,请参阅 Windows 调试。
激活特殊池选项
可以使用驱动验证管理器或 Verifier.exe 命令行为一个或多个驱动程序激活特殊池功能。 有关详细信息,请参阅 “选择驱动程序验证程序选项”。
注释
若要按池标记或分配大小激活特殊池功能,或者要设置 “验证开始 ”(检测不足)和 “验证结束 ”(检测溢出)对齐方式,请使用 全局标志实用工具;这些对齐设置适用于所有特殊池分配。
在命令行
在命令行中,特殊池选项由 位 0 (0x1) 表示。 若要激活特殊池,请使用标志值0x1或向标志值添加0x1。 例如:
verifier /flags 0x1 /driver MyDriver.sys下一次启动后,该功能将处于活动状态。
Yyou 还可以通过将 /volatile 参数添加到命令来激活和停用特殊池,而无需重新启动计算机。 例如:
verifier /volatile /flags 0x1 /adddriver MyDriver.sys此设置立即生效,但在关闭或重新启动计算机时会丢失。 有关详细信息,请参阅 “使用易失性设置”。
标准设置中还包括特殊池功能。 例如:
verifier /standard /driver MyDriver.sys使用驱动程序验证管理器
- 选择 “创建自定义设置”(面向代码开发人员), 然后单击“ 下一步”。
- 从完整列表中选择单个设置。
- 选择(检查) 特殊池。
标准设置中还包括特殊池功能。 若要使用此功能,请在驱动程序验证程序管理器中,单击“ 创建标准设置”。